#include <vcl.h>
#pragma hdrstop

// Section des includes
#include "MTAG_Outils.h"  //Pour MTAG_CTREEX
#include <stdio.h>
#include "CTreeX.h"
#include "CTEdit.h"
#include "Cpctrl.h"
#include "eic.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
#define MODULE_TAG    MTAG_CTREEX
//---------------------------------------------------------------------------
// Taille des écrans pour un assistant en 640x480
#define WIN_HEIGHT_640 350
#define WIN_WIDTH_640  460
// Taille des écrans pour un assistant en 800x600
#define WIN_HEIGHT_800 470
#define WIN_WIDTH_800  620
// Taille de l'arbre dans un assistant
#define TV_WIDTH       165
//---------------------------------------------------------------------------
#define LENGTH_TEXT    30

#define HEIGHT_BTN     25         // Hauteur d'un bouton
#define HEIGHT_GRPBOX   8         // Hauteur du header d'un TGroupBox
#define WIDTH_BTN      70         // 70 % de la taille du parent
#define NB_MENUS       11         // Nombre de type d'écran existant
#define MARGIN_BTN     15         // Valeur de la propriété Margin des BitBtns
//---------------------------------------------------------------------------
#define SPDRETURN      "SpdBtnReturn"
#define SPDPRIOR       "SpdBtnPrior"
#define SPDNEXT        "SpdBtnNext"
#define SPDPRINT       "SpdBtnPrint"
#define SPDPREVIEW     "SpdBtnPreview"
#define SPDEXIT        "SpdBtnExit"
#define LISTENAME      "EICListe"
//---------------------------------------------------------------------------
//#define IS_ENABLED( x) ((x)->Enabled && (x)->EnabledInternal)
//---------------------------------------------------------------------------
const int EnableBMP [NB_MENUS] = {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 };
const int DisableBMP[NB_MENUS] = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21 };
//---------------------------------------------------------------------------
bool __fastcall IS_ENABLED( CNodeInfos *nodeinfos)
{
  return ( nodeinfos->Enabled && nodeinfos->EnabledInternal);
}
//---------------------------------------------------------------------------
inline int __fastcall ICON( CTree *pTree, CNodeInfos *nodeinfos)
{
  int nIcon = nodeinfos->Icon;
  if(( nIcon<0) || ( nIcon>=pTree->Images->Count)) nIcon = 0;
  return nIcon;
}
//---------------------------------------------------------------------------
// ValidCtrCheck est utilisé pour être sûr que les composants créés ne
// contiennent aucune fonction virtuelle pure.
//
static inline void ValidCtrCheck(CTree *)
{
    new CTree(NULL);
}
/***************************************************************************/
/*
/*  Constructeurs et destructeurs de l'objet CTree
/*  + les fonctions de déinitialisation de l'objet
/*
/*  Fonctions:
/*  ----------
/*
/***************************************************************************/
//---------------------------------------------------------------------------
__fastcall CTree::CTree(TComponent* Owner)
    : TCustomTreeView(Owner)
{
  try {
    // Initialisation des variables membre de la classe
    m_pbtnReturn           = NULL;
    m_pbtnPrior            = NULL;
    m_pbtnNext             = NULL;
    m_pbtnPrint            = NULL;
    m_pbtnPreview          = NULL;
    m_NodesInfos           = NULL;
    m_pScrOpen             = NULL;
    m_pBtnAction           = NULL;
    m_pfrmCurrent          = NULL;
    m_CommonNode           = NULL;
    m_pPageCtrl            = NULL;
    m_pInstances           = NULL;
//    m_OnDataChange         = NULL;
    m_pOnKeyDown           = NULL;
    m_pOnKeyUp             = NULL;
    m_pOnKeyPress          = NULL;
    m_pNodeCollapsing      = NULL;
    m_pfncOnClose          = NULL;
    m_pMainForm            = NULL;
    m_pnlPageFooter        = NULL;
    m_lstEICIcons          = NULL;
    m_Mask                 = 0xFFFF;
    m_bCanCollapse         = false;
    m_bResizeable          = false;
    m_bInitEvKey           = false;
    m_bExit                = false;
    m_bEditCTree           = false;
    m_bUseCustomIcons      = false;
    m_bExitAss             = false;
    m_bOnCloseQueryEnCours = false;
    HideSelection          = false;
    TabStop                = false;
    ReadOnly               = true;
    ShowRoot               = false;
    m_AutoLettre           = true;
    m_pPushInCTree         = NULL;

    m_NodesInfos           = new TList;
    m_pScrOpen             = new TList;
    m_pBtnAction           = new TList;
    m_pInstances           = new TStringList;
    m_nSizeAssist          = SCR800x600;
    // Mise en place des évènements
    OnChange          = EvOnChange;
    OnChanging        = EvOnChanging;
    OnExpanding       = EvOnExpanding;
    OnCollapsing      = EvOnCollapsing;
    OnDeletion        = EvOnDeletion;

    m_hwndFocusedAfterError = NULL;
    m_pfncOnChangeScreen    = NULL;
    m_pfncOnChangingScreen  = NULL;

    if( (_CodePartenaire==ecp_Fiduciaire_DR) || (_CodePartenaire==ecp_Fiduciaire_TP)) Color = clBtnFace;
    m_bUseCustomIcons = ( (_CodePartenaire==ecp_Fiduciaire_DR) || (_CodePartenaire==ecp_Fiduciaire_TP));    

    m_Splash = NULL;
  } catch (Exception &e) {
    throw EUser( TAG(5), e);
  }
}
//---------------------------------------------------------------------------
__fastcall CTree::~CTree(void)
{
  if ( m_bInitEvKey) {
    m_pMainForm->OnKeyDown  = m_pOnKeyDown;
    m_pMainForm->OnKeyUp    = m_pOnKeyUp;
    m_pMainForm->OnKeyPress = m_pOnKeyPress;
  }
  if (Parent!=NULL) Parent = dynamic_cast<TWinControl *>(Owner);

  // Efface les données spécifique de chaque node
  ClearExtraDatas();
  // Détruit les listes des extras-données et des écrans
  delete m_NodesInfos;
  delete m_pBtnAction;
  delete m_pScrOpen;
  delete m_pInstances;
}
//---------------------------------------------------------------------------
/***************************************************************************/
/*
/*  Fonction d'initialisation de l'application et de déinitialisation
/*
/*  Fonctions:
/*  ----------
/*    ExecuteApplication       -> Appelé par l'utilisateur afin de
/*                                donné un pointeur sur la fenêtre parent
/*                                du TreeView et de donné le masque d'affichage
/*                                des écrans
/*    ClearExtraDatas          -> Efface les données spéciques à
/*                                chaque node
/*    ConnectToHoteApplication -> Recherche des composants spécifiques
/*                                dans l'application afin de réagir
/*                                à certain évènement
/*    CreateTree               -> Créer et affiche l'arbre
/*    AddMenu                  -> Ajoute un écran dans l'arbre
/*    AddChildMenu             -> Ajoute un écran enfant à un écran
/*    CreateChildScreensLevel  -> Détermine et donne un niveau pour chaque écran
/*    CreateScreensLevel       ->                     ""
/*    VerifyAllScreens         -> Vérifie que tous les écrans existe ds la DLL
/*
/***************************************************************************/
//---------------------------------------------------------------------------
bool __fastcall CTree::InitAssistant( HINSTANCE HInstance, short sMask /* = 0xFFFF */)
{
  m_Mask = sMask;
  SetInstance( HInstance, this);
  return VerifyAllScreens();
}
//---------------------------------------------------------------------------
void __fastcall CTree::ExecuteAssistant(TWinControl *pWinParent, bool bFenAssistantSeule)
{
  Graphics::TBitmap *bmpPrev, *bmpNext, *bmpCustom;
  TForm             *pfrmParent;
  EICTag             nTag;

  try {
                    ASSERT( m_pInstances->Count!=0); // L'instance de la DLL de l'application n'a pas été initialisée

                    SetLoadingScreen( -1);

                    // Positionne le TreeView dans la fenêtre
    nTag = TAG(10); Align  = alLeft;
                    Width  = TV_WIDTH;
                    Parent = pWinParent;

                    // Intercepte le CloseQuery de la fenêtre qui contient le TreeView
                    pfrmParent = dynamic_cast<TForm *>(Parent);
                    ASSERT( pfrmParent); pfrmParent->OnCloseQuery = EvOnCloseQuery;

                    // Charge les bitmaps du TreeView depuis la ressource
                    Graphics::TBitmap *pBitmap = NULL;
                    pBitmap = new Graphics::TBitmap();
                    pBitmap->LoadFromResourceName(( int)HInstance, "ICONES_CTREE");

                    m_lstEICIcons         = new TImageList( this);
                    m_lstEICIcons->Masked = true;
                    m_lstEICIcons->AddMasked( pBitmap, pBitmap->Canvas->Pixels[0][0]);

                    delete pBitmap;

                    if(( Images==NULL) || !m_bUseCustomIcons) Images = m_lstEICIcons;

/*
    nTag = TAG(12); Images = new TImageList(Owner);
                    Images->ResInstLoad((int)HInstance, rtBitmap, "ICONES_CTREE", clMaroon);*/
//                    m_Mask  = sMask;

                    // Création du splitter
    nTag = TAG(14); TSplitter *pSplitter = NULL;
                    if( !bFenAssistantSeule)
                    {
         		        pSplitter = new TSplitter(this);
                        pSplitter->Left      = Left + Width + 1;
                        pSplitter->Visible   = false;
                        pSplitter->Parent    = Parent;
                        pSplitter->MinSize   = 1;                       // Taille minimale du TreeView
                    }
                    // Création de la barre CPageControl
    nTag = TAG(16); m_pPageCtrl          = new CPageControl(this);
                    m_pPageCtrl->Align   = alClient;
                    m_pPageCtrl->Visible = false;
                    m_pPageCtrl->Parent  = Parent;
                    SetPanelPageFooter( PageFooter);


                    // Création des objets bitmaps
    nTag = TAG(20); bmpPrev   = new Graphics::TBitmap();
                    bmpNext   = new Graphics::TBitmap();
                    bmpCustom = new Graphics::TBitmap();

    nTag = TAG(22); ConnectToHoteApplication();
                    m_lstEICIcons->GetBitmap(2*NB_MENUS  , bmpPrev  );
                    m_lstEICIcons->GetBitmap(2*NB_MENUS+1, bmpNext  );
                    m_lstEICIcons->GetBitmap(2*NB_MENUS+2, bmpCustom);
                    // Initialise le panel à onglets
                    m_pPageCtrl->SetCTree(this, bmpPrev, bmpNext, bmpCustom);

    nTag = TAG(24); CreateTree();
                    if ( m_AutoLettre) CreateScreensLevel();
                    // Mise en place du nouveau gestionnaire sur le OnKeyDown,
                    // OnKeyPress et OnKeyUp de la fiche principale
                    if( !CMainForm || (pWinParent->Parent == NULL)) m_pMainForm = dynamic_cast<CForm*>( pWinParent);
                                                               else m_pMainForm = CMainForm;
                    ASSERT( m_pMainForm);
    nTag = TAG(26); m_pMainForm->KeyPreview = true;
                    m_pOnKeyDown            = m_pMainForm->OnKeyDown;
                    m_pMainForm->OnKeyDown  = EvOnFormKeyDown;
                    m_pOnKeyUp              = m_pMainForm->OnKeyUp;
                    m_pMainForm->OnKeyUp    = EvOnFormKeyUp;
                    m_pOnKeyPress           = m_pMainForm->OnKeyPress;
                    m_pMainForm->OnKeyPress = EvOnFormKeyPress;
                    m_bInitEvKey            = true;

    nTag = TAG(28); // Positionne sur le premier écran visible
                    int nFirstVisible = GetFirstChild( -1);
                    while(( nFirstVisible!=0) && !FindNode( nFirstVisible)->Visible)
                      nFirstVisible = GetNextChild( -1, nFirstVisible);
                    ASSERT( nFirstVisible!=0);

                    if( bFenAssistantSeule)
                    {
                    	m_pPageCtrl->Header = 0;
                    	Visible = false;
                    }
                    SetSelectedMenuInternal( nFirstVisible);
                    if( pSplitter) pSplitter->Visible = true;
                    m_pPageCtrl->Visible = true;

  } catch ( Exception &e) {
    throw EUser( nTag, e);
  }
}
//---------------------------------------------------------------------------
void __fastcall CTree::GetEtatPriorNext ( BYTE &bPriorActif, BYTE &bNextActif)
{
  try {
    bPriorActif = m_pbtnPrior->Enabled;
    bNextActif  = m_pbtnNext->Enabled;
  } catch (Exception &e) {
    throw EUser( TAG(29), e);
  }
}
//---------------------------------------------------------------------------
void __fastcall CTree::ConnectToHoteApplication()
{
  try {
    // Recherche les SpeedButtons dans le contrôle parent (normalement la fenêtre principale)
    m_pbtnReturn  = dynamic_cast<TSpeedButton *>(Parent->FindComponent(SPDRETURN )); ASSERT(m_pbtnReturn );
    m_pbtnPrior   = dynamic_cast<TSpeedButton *>(Parent->FindComponent(SPDPRIOR  )); ASSERT(m_pbtnPrior  );
    m_pbtnNext    = dynamic_cast<TSpeedButton *>(Parent->FindComponent(SPDNEXT   )); ASSERT(m_pbtnNext   );
    m_pbtnPrint   = dynamic_cast<TSpeedButton *>(Parent->FindComponent(SPDPRINT  )); ASSERT(m_pbtnPrint  );
    m_pbtnPreview = dynamic_cast<TSpeedButton *>(Parent->FindComponent(SPDPREVIEW)); ASSERT(m_pbtnPreview);
    // Place les évènements associés à chaque composant
    AddButtonAction( m_pbtnReturn , BA_PARENT_RETURN);
    AddButtonAction( m_pbtnPrior  , BA_PRIOR        );
    AddButtonAction( m_pbtnNext   , BA_NEXT         );
    AddButtonAction( m_pbtnPrint  , BA_PRINT        );
    AddButtonAction( m_pbtnPreview, BA_PREVIEW      );
  } catch (Exception &e) {
    throw EUser( TAG(30), e);
  }
}
//---------------------------------------------------------------------------
void __fastcall CTree::AddButtonAction( TSpeedButton *sbNew, BUTTON_ACTION eAction)
{
  switch( eAction) {
    case BA_PARENT_RETURN : sbNew->OnClick = EvOnClickReturn;  break;
    case BA_PRIOR         : sbNew->OnClick = EvOnClickPrior;   break;
    case BA_NEXT          : sbNew->OnClick = EvOnClickNext;    break;
    case BA_PRINT         : sbNew->OnClick = EvOnClickPrint;   break;
    case BA_PREVIEW       : sbNew->OnClick = EvOnClickPreview; break;
    default               : ASSERT( false);                    break;
  }
  sbNew->Tag = ( int)eAction;
  m_pBtnAction->Add( sbNew);
}
//---------------------------------------------------------------------------
void __fastcall CTree::SetButtonAction( BUTTON_ACTION eAction, bool bEnable)
{
  TList *pBtnAction = GetParentCTree()->m_pBtnAction;
  for( int i=pBtnAction->Count-1; i>=0; i--) {
    TSpeedButton *sbAction = ( TSpeedButton*)pBtnAction->Items[i];
    if(( BUTTON_ACTION)sbAction->Tag==eAction) sbAction->Enabled = bEnable;
  }
}
//---------------------------------------------------------------------------
void __fastcall CTree::CreateTree()
{
  CNodeInfos *nodeinfos;
  CNodeInfos *pParentNodeInfos;
  CNodeInfos *pBrotherNodeInfos;
  AnsiString  strText;

  // Initialisation des données de l'arbre
  Selected = NULL;
  UnLoadScreens(); m_pfrmCurrent = NULL;
  for( int i=0; i<m_NodesInfos->Count; i++) (( CNodeInfos*)m_NodesInfos->Items[i])->Node = NULL;
  OnDeletion = NULL; Items->Clear(); OnDeletion = EvOnDeletion;

  // Affiche l'arbre
  for(int i=0; i<m_NodesInfos->Count; i++) {
    nodeinfos = ( CNodeInfos *)m_NodesInfos->Items[i];
    strText   = ConvertText( nodeinfos->Text);
    if ( !nodeinfos->Visible || (( nodeinfos->Mode & nodeinfos->Tree->m_Mask)==0)) continue;
    // Affichage du texte dans l'arbre
    if( nodeinfos->TagBrother!=-1) {
      if(( pBrotherNodeInfos=FindNode( nodeinfos->TagBrother))!=NULL) {
        nodeinfos->Node = Items->Insert( pBrotherNodeInfos->Node, strText);
        TAG_NODE( nodeinfos->Node) = nodeinfos->Tag;
      }
    } else {
      if( nodeinfos->TagParent!=-1) {
        pParentNodeInfos = FindNode( nodeinfos->TagParent);
        if( pParentNodeInfos->Node!=NULL) {
          nodeinfos->Node = Items->AddChild( pParentNodeInfos->Node, strText);
          TAG_NODE( nodeinfos->Node) = nodeinfos->Tag;
        }
      } else {
        nodeinfos->Node = Items->Add( NULL, strText);
        TAG_NODE( nodeinfos->Node) = nodeinfos->Tag;
      }
    }

    if ( IS_CURRENTELEM( nodeinfos->WindowStyle)) SetBoldNode( true, nodeinfos->Node);
    // Mise en place des bitmaps si l'écran a été insérer dans l'arbre
    if ( nodeinfos->Node) SetInternalEnableScreen( nodeinfos->Enabled, nodeinfos->Tag);
  }
/*
  for(int i=0; i<m_NodesInfos->Count; i++) {
    nodeinfos = ( CNodeInfos *)m_NodesInfos->Items[i];
    if ( nodeinfos->Visible && (nodeinfos->Mode & m_Mask)) {
      // Affichage du texte dans l'arbre
      if (nodeinfos->TagParent != -1) {
        if (FindNode(nodeinfos->TagParent)->Node!=NULL) {
          nodeinfos->Node = Items->AddChild(FindNode(nodeinfos->TagParent)->Node, ConvertText(nodeinfos->Text));
          TAG_NODE(nodeinfos->Node) = nodeinfos->Tag;
        }
      } else {
          nodeinfos->Node = Items->Add(NULL, ConvertText(nodeinfos->Text));
          TAG_NODE(nodeinfos->Node) = nodeinfos->Tag;
      }

      if (IS_CURRENTELEM(nodeinfos->WindowStyle)) SetBoldNode(true, nodeinfos->Node);
      // Mise en place des bitmaps si l'écran a été insérer dans l'arbre
      if ( nodeinfos->Node) SetInternalEnableScreen(nodeinfos->Enabled, nodeinfos->Tag);
    }
  }
*/
}
//---------------------------------------------------------------------------
void __fastcall CTree::AddMenu(int TagParent, TNodeInfos &infos)
{
  try {
    if (TagParent==-1) infos.TagParent = TagParent;
                  else infos.TagParent = FindNodeEdit(TagParent)->TagParent;
    m_NodesInfos->Add( new CNodeInfos( infos, this));
  } catch (Exception &e) {
    throw EUser( TAG(34), e);
  }
}
//---------------------------------------------------------------------------
void __fastcall CTree::AddChildMenu(int TagParent, TNodeInfos &infos)
{
  try {
    infos.TagParent = TagParent;
    m_NodesInfos->Add( new CNodeInfos( infos, this));
  } catch (Exception &e) {
    throw EUser( TAG(36), e);
  }
}
//---------------------------------------------------------------------------
void __fastcall CTree::ClearExtraDatas()
{
  for(int i=0; i<m_NodesInfos->Count; i++) delete ( CNodeInfos*)m_NodesInfos->Items[i];
  m_NodesInfos->Clear();
}
//---------------------------------------------------------------------------
void __fastcall CTree::CreateChildScreensLevel(TTreeNode *Node)
{
  CNodeInfos *nodeinfos;
  char        nLevel = 0;

  for(int i=0; i<Node->Count; i++) {
    nodeinfos = FindNode(Node->Item[i]);
    if (!IS_CURRENTELEM(nodeinfos->WindowStyle)) {
      nodeinfos->Level = nLevel++;
      CreateChildScreensLevel(nodeinfos->Node);
    }
  }
}
//---------------------------------------------------------------------------
// Permet de générer une lettre pour chaque écran de premier niveau
// et appelle ensuite CreateChildScreensLevel qui lui s'occupe de générer
// toutes les autres lettres sur N niveaux
void __fastcall CTree::CreateScreensLevel()
{
  CNodeInfos *nodeinfos;
  char        nLevel = 0;

  for(int i=0; i<Items->Count; i++) {
    nodeinfos = FindNode(Items->Item[i]);
    if (nodeinfos->Node->Parent==NULL) {
      if (!IS_CURRENTELEM(nodeinfos->WindowStyle)) nodeinfos->Level = nLevel++;
      CreateChildScreensLevel(nodeinfos->Node);
    }
  }
}
//---------------------------------------------------------------------------
bool __fastcall CTree::VerifyAllScreens()
{
  CNodeInfos          *nodeinfos;
  AnsiString           strLostScreens;

  // Essaye de trouver les fonctions qui permettent d'instancier
  // chaque écran et crée une chaine contenant la liste des écrans
  // qui ne peuvent être instancié
  for( int i=0; i<m_NodesInfos->Count; i++) {
    nodeinfos = ( CNodeInfos*)m_NodesInfos->Items[i];
    if (  IS_CURRENTELEM(nodeinfos->WindowStyle)) continue;
    if ( !GetScreenInstanceProc( nodeinfos)) strLostScreens = strLostScreens + "     " + nodeinfos->ClassName + "\n";
  }

  // En mode DEBUG, on affiche la liste des écrans manquant dans
  // la DLL de l'assistant et renvoie toujours 'true'
  // Sinon en mode RELEASE, renvoie 'true' seulement si tous
  // les écrans ont été trouvés
#ifdef _DEBUG
  if ( !strLostScreens.IsEmpty()) {
    strLostScreens = "Ecrans introuvables dans la DLL :\n" + strLostScreens;
    ::EICAttention( strLostScreens);
  }
  return true;
#else
  return strLostScreens.IsEmpty();
#endif
}
//---------------------------------------------------------------------------
/***************************************************************************/
/*
/*  Fonctions d'écriture et de lecture des données spécifiques
/*  de chaque node dans le fichier .dfm.
/*  + fonction de génération d'un fichier header à inclure
/*  au projet
/*
/*  Fonctions:
/*  ----------
/*    DefineProperties   -> Surcharge de la fonction DefineProperties
/*                          afin de pourvoir écrire les extra-données
/*    ReadDatas          -> Lecture des données de la dfm via un flux
/*    ReadInteger        -> Lecture d'un entier 32 bits
/*    ReadBool           -> Lecture d'un booléen
/*    ReadShort          -> Lecture d'un entier court 16 bits
/*    ReadString         -> Lecture d'un chaine
/*                          Lecture de la longeur sur un entier +
/*                          lecture de la chaine
/*    WriteDatas         -> Ecriture des données de la dfm via un flux
/*    WriteInteger       -> Ecriture d'un entier 32 bits
/*    WriteBool          -> Ecriture d'un booléen
/*    WriteShort         -> Ecriture d'un entier court 16 bits
/*    Writetring         -> Ecriture d'un chaine
/*                          Ecriture de la longeur sur un entier +
/*                          Ecriture de la chaine
/*    GenerateHeaderFile -> Création du fichier .h du nom du composant
/*
/***************************************************************************/
//---------------------------------------------------------------------------
void __fastcall CTree::DefineProperties(TFiler* Filer)
{
  inherited::DefineProperties(Filer);
  Filer->DefineBinaryProperty("EICDatas", ReadDatas, WriteDatas, true);
}
//---------------------------------------------------------------------------
int __fastcall CTree::ReadInteger(TStream *Stream)
{
  int nValue;
  Stream->ReadBuffer(&nValue, sizeof(nValue));
  return nValue;
}
//---------------------------------------------------------------------------
char __fastcall CTree::ReadChar(TStream *Stream)
{
  char cValue;
  Stream->ReadBuffer(&cValue, sizeof(cValue));
  return cValue;
}
//---------------------------------------------------------------------------
bool __fastcall CTree::ReadBool(TStream *Stream)
{
  bool bValue;
  Stream->ReadBuffer(&bValue, sizeof(bValue));
  return bValue;
}
//---------------------------------------------------------------------------
short __fastcall CTree::ReadShort(TStream *Stream)
{
  short nValue;
  Stream->ReadBuffer(&nValue, sizeof(nValue));
  return nValue;
}
//---------------------------------------------------------------------------
AnsiString __fastcall CTree::ReadString(TStream *Stream)
{
  char szValue[256];
  int  nLength = ReadInteger( Stream); ASSERT( nLength<256);
  Stream->ReadBuffer(szValue, nLength);
  return AnsiString(szValue);
}
//---------------------------------------------------------------------------
void __fastcall CTree::ReadDatas(TStream *Stream)
{
  TNodeInfos infos;
  int        nEcrans; // Nombre d'écrans enregistrés dans le DFM

  try {
    m_nVersion = ReadShort  (Stream);
    nEcrans    = ReadInteger(Stream);

    // Les versions inférieurs à la version 1.04 ne sont plus gérés
    if (m_nVersion< (short)0x0104) throw EUser( TAG(38), "Version de CTree incompatible avec la version 1.04 !");
    if (m_nVersion>=(short)0x0106) m_szPathHeader = ReadString( Stream);
    if (m_nVersion>=(short)0x0108) {
      m_nSizeAssist = (int)ReadChar( Stream);
           if ( m_nSizeAssist==SCR640x480) { m_nHeightScr = WIN_HEIGHT_640; m_nWidthScr = WIN_WIDTH_640; }
      else if ( m_nSizeAssist==SCR800x600) { m_nHeightScr = WIN_HEIGHT_800; m_nWidthScr = WIN_WIDTH_800; }
      else ASSERT( false);
    } else {
      // Avant la version 1.08 tous les écrans sont obligatoirement en 640x480
      m_nHeightScr = WIN_HEIGHT_640;
      m_nWidthScr  = WIN_WIDTH_640;
    }
    if ( m_nVersion>=( short)0x0109) m_bResizeable = ReadBool( Stream);

    // Lit les extra-datas de chaque node dans la DFM
    for(int i=0; i<nEcrans; i++) {
      InitStandardInfos(&infos);
      infos.Tag          = ReadInteger(Stream);
      infos.TagParent    = ReadInteger(Stream);
      infos.TagMenu      = ReadInteger(Stream);
      infos.Text         = ReadString (Stream);
      infos.Enabled      = ReadBool   (Stream);
      infos.Visible      = ReadBool   (Stream);
      infos.WindowStyle  = ReadInteger(Stream);
      infos.Mode         = ReadShort  (Stream);
      infos.ClassName    = ReadString (Stream);
      infos.DefineName   = ReadString (Stream);
      infos.MenuCreate   = ReadBool   (Stream);
      if (IS_LISTE(infos.WindowStyle)) {
        infos.FieldName  = ReadString (Stream);
        infos.KeyField   = ReadString (Stream);
        infos.ListField  = ReadString (Stream);
        if (m_nVersion>=(short)0x0105) infos.HaveList = ReadBool(Stream);
      }
      if (IS_SCR_LISTE(infos.WindowStyle))
        infos.DisplayBar = ReadBool   (Stream);
        if (m_nVersion>=(short)0x0107) infos.Level    = ReadChar(Stream);
      if( m_nVersion>=(short)0x010a) infos.Icon = ReadInteger( Stream);

      m_NodesInfos->Add( new CNodeInfos( infos, this));
    }

  } catch (Exception &e) {
    throw EUser( TAG(40), e);
  }
}
//---------------------------------------------------------------------------
void __fastcall CTree::WriteInteger(int nValue, TStream *Stream)
{
  Stream->WriteBuffer(&nValue, sizeof(nValue));
}
//---------------------------------------------------------------------------
void __fastcall CTree::WriteChar(char cValue, TStream *Stream)
{
  Stream->WriteBuffer(&cValue, sizeof(cValue));
}
//---------------------------------------------------------------------------
void __fastcall CTree::WriteBool(bool bValue, TStream *Stream)
{
  Stream->WriteBuffer(&bValue, sizeof(bValue));
}
//---------------------------------------------------------------------------
void __fastcall CTree::WriteShort(short nValue, TStream *Stream)
{
  Stream->WriteBuffer(&nValue, sizeof(nValue));
}
//---------------------------------------------------------------------------
void __fastcall CTree::WriteString( const AnsiString &strValue, TStream *Stream)
{
  int nLength = strValue.Length() + 1;  // + 1 pour inclure le zéro terminal
  WriteInteger( nLength, Stream);
  Stream->WriteBuffer( strValue.c_str(), nLength);
}
//---------------------------------------------------------------------------
void __fastcall CTree::WriteDatas(TStream *Stream)
{
  CNodeInfos *nodeinfos;

  try {
    WriteShort  ( VERSION                   , Stream);
    WriteInteger( m_NodesInfos->Count       , Stream);
    WriteString ( m_szPathHeader.UpperCase(), Stream);
    WriteChar   ( (char)m_nSizeAssist       , Stream);
    WriteBool   ( m_bResizeable             , Stream);

    for(int i=0; i<m_NodesInfos->Count; i++) {
      nodeinfos = (CNodeInfos *)m_NodesInfos->Items[i];

      WriteInteger(nodeinfos->Tag         , Stream);
      WriteInteger(nodeinfos->TagParent   , Stream);
      WriteInteger(nodeinfos->TagMenu     , Stream);
      WriteString (nodeinfos->Text        , Stream);
      WriteBool   (nodeinfos->Enabled     , Stream);
      WriteBool   (nodeinfos->Visible     , Stream);
      WriteInteger(nodeinfos->WindowStyle , Stream);
      WriteShort  (nodeinfos->Mode        , Stream);
      WriteString (nodeinfos->ClassName   , Stream);
      WriteString (nodeinfos->DefineName  , Stream);
      WriteBool   (nodeinfos->MenuCreate  , Stream);
      if (IS_LISTE(nodeinfos->WindowStyle)) {
       WriteString(nodeinfos->FieldName   , Stream);
       WriteString(nodeinfos->KeyField    , Stream);
       WriteString(nodeinfos->ListField   , Stream);
       WriteBool  (nodeinfos->HaveList    , Stream);
      }
      if (IS_SCR_LISTE(nodeinfos->WindowStyle))
        WriteBool (nodeinfos->DisplayBar  , Stream);
      WriteChar   (nodeinfos->Level       , Stream);
      WriteInteger(nodeinfos->Icon        , Stream);
    }
    // Génère un fichier .h
    GenerateHeaderFile();

  } catch (Exception &e) {
    throw EUser( TAG(42), e);
  }
}
//---------------------------------------------------------------------------
void __fastcall CTree::GenerateHeaderFile()
{
  FILE *f;
  CNodeInfos *nodeinfos;
  AnsiString  szFileLine;

  if ( !m_bEditCTree) return;

  // Demande confirmation pour créer le fichier des defines
  if (!EICQuestion("Voulez-vous créer le fichier qui contient les 'define's des écrans ?",
                   EICFormat("Création du fichier %s.H", Name.UpperCase().c_str()).c_str(), 0)) return;

  if (!m_szPathHeader.IsEmpty() && (m_szPathHeader[m_szPathHeader.Length()]!='\\')) m_szPathHeader += "\\";
  if ((f = fopen(AnsiString(m_szPathHeader+Name+".h").c_str(), "wt")) == NULL) {
    EICErreur(EICFormat("Impossible de créer le fichier %s.H !", Name.UpperCase().c_str()).c_str());
    return;
  }

  fputs("// Ce fichier est un fichier généré.\n", f);
  fputs("// Il ne doit pas être modifié manuellement.\n", f);
  fputs("// (C)opyright Editions Informatiques Comptables (1998).\n\n", f);
  szFileLine = "// Fichier généré avec la version " + IntToHex((VERSION>>8) & 0x00ff,1) + "." + IntToHex(VERSION & 0x00ff,2) + "\n\n";
  fputs(szFileLine.c_str(), f);

  for(int i=0; i<m_NodesInfos->Count; i++) {
    nodeinfos  = (CNodeInfos *)m_NodesInfos->Items[i];
    szFileLine = nodeinfos->DefineName;
    // Si le define comprent des espaces, on les renplace par des soulignés
    for(int j=1; j<=szFileLine.Length(); j++)
      if (szFileLine[j]==' ') szFileLine[j]='_';
    szFileLine = "#define " + szFileLine;
    while (szFileLine.Length() < LENGTH_TEXT) szFileLine = szFileLine + " ";
    szFileLine = szFileLine + " 0x" + IntToHex(nodeinfos->Tag, 8);
    szFileLine = szFileLine + "  // " + nodeinfos->Text + "\n";
    fputs(szFileLine.c_str(), f);
  }

  fclose(f);
}
//---------------------------------------------------------------------------
/***************************************************************************/
/*
/*  Fonctions de recherche des informations d'un node et d'initialisation
/*  de la structure par défaut
/*
/*  Fonctions:
/*  ----------
/*    InitStandardInfos     -> Initialisation de la structure
/*                             TNodeInfos par défaut
/*    FindNodeEdit(int)     -> Recherche les extra-infos d'un node
/*                             en fonction de son Tag utilisé
/*                             seulement par l'éditeur
/*    FindNode (int)        -> Recherche les extra-infos d'un node
/*                             en fonction de son Tag
/*    FindNode (TTreeNode)  -> Recherche les extra-infos d'un node
/*                             en fonction d'un pointeur TTreeNode
/*                             donné par le TCustomTreeView
/*
/***************************************************************************/
//---------------------------------------------------------------------------
void __fastcall CTree::InitStandardInfos(TNodeInfos *infos)
{
  int  i, j, max, value;
  char c;

  infos->Visible         = true;
  infos->Enabled         = true;
  infos->EnabledInternal = true;
  infos->MenuCreate      = false;
  infos->WindowStyle     = SCR_SAISIE_M;
  // Calcule un numéro de tag (tag le plus grand déjà existant + 1)
  for(max=0,i=0; i<m_NodesInfos->Count; i++) {
    CNodeInfos *nodeinfos = (CNodeInfos *)m_NodesInfos->Items[i];
    if (nodeinfos->Tag > max) max = nodeinfos->Tag;
    // Convertit le numéro du nom de la classe en entier
    if ((nodeinfos->ClassName!=EmptyStr) && (nodeinfos->ClassName.Pos("TScreen")==1)) {
      for(value=0,j=8; j<12; j++) {
        c = nodeinfos->ClassName[j];
        if ((c>='0') && (c<='9')) value = value*16 + (c-'0');
        else if ((c>='A') && (c<='F')) value = value*16 + 10 + (c-'A');
      }
      if (value > max) max = value;
    }
    // Convertit le numéro du nom du Tag en entier
    if (nodeinfos->DefineName.Pos("TAG")==1) {
      for(value=0,j=4; j<8; j++) {
        c = nodeinfos->DefineName[j];
        if ((c>='0') && (c<='9')) value = value*16 + (c-'0');
        else if ((c>='A') && (c<='F')) value = value*16 + 10 + (c-'A');
      }
      if (value > max) max = value;
    }
  }
  infos->Tag         = (max+1);
  infos->TagBrother  = -1;
  infos->TagParent   = -1;
  infos->TagMenu     = 100;
  infos->Text        = EmptyStr;
  infos->KeyField    = EmptyStr;
  infos->ListField   = EmptyStr;
  infos->FieldName   = EmptyStr;
  infos->ClassName   = "TScreen" + IntToHex(infos->Tag, 4);
  infos->DefineName  = "TAG"     + IntToHex(infos->Tag, 4);
  infos->Mode        = 0xFFFF;
  infos->DisplayBar  = true;
  infos->HaveList    = true;
  infos->Level       = 0;
  infos->Icon        = -1;
}
//---------------------------------------------------------------------------
CNodeInfos *__fastcall CTree::FindNodeEdit(int nTag)
{
  for(int i=m_NodesInfos->Count-1; i>=0; i--) {
    if ( ((CNodeInfos *)m_NodesInfos->Items[i])->Tag == nTag )
      return (CNodeInfos *)m_NodesInfos->Items[i];
  }
  return NULL;
}
//---------------------------------------------------------------------------
CNodeInfos *__fastcall CTree::FindNode(int nTag)
{
  if(!(( nTag>=1) && ( nTag<=m_NodesInfos->Count)))
    return (CNodeInfos *)m_NodesInfos->Items[0];

  ASSERT(( nTag>=1) && ( nTag<=m_NodesInfos->Count) );
  return (CNodeInfos *)m_NodesInfos->Items[ nTag-1 ];
}
//---------------------------------------------------------------------------
CNodeInfos *__fastcall CTree::FindNode(TTreeNode *Node)
{
  return FindNode( TAG_NODE( Node));
}
//---------------------------------------------------------------------------
/***************************************************************************/
/*
/*  Fonctions de services bien utile
/*
/*  Fonctions:
/*  ----------
/*    SelectedRealAbsoluteIndex -> Renvoie l'index absolue de
/*                                 l'élément sélectionné
/*    IsSoonOf                  -> Détermine si l'écran donné par le Tag
/*                                 existe dans la branche donné par TagParent
/*    FindControlTag            -> Recherche un control grâce à son
/*                                 Tag à l'intérieur d'un autre control
/*    GetParentForm(int)        -> Renvoie la form correspondant dans la
/*                                 liste des écrans chargés
/*    GetParentForm             -> Renvoie l'avant dernière form chargée
/*    SetEnableAllBranche       -> Enable tous les fils d'un Node
/*    DisableSystemButtons      -> Grise les boutons en fonction de l'écran
/*                                 actuellement chargé
/*    FindCommonParent          -> Renvoie le Node commun à deux branches
/*    SetTextMenu               -> Modifie le texte d'un écran
/*    DisplayBranche            -> Rend visible une branche
/*    ChangeCurrentElement      -> Se produit lorsqu'il y a au
/*                                 des changements dans une table
/*                                 afin de mettre à jour le menu
/*                                 d'un écran liste
/*    ConvertText               -> Convertit un texte pour être affiché
/*                                 dans l'arbre. Enlève le \t
/*    NextItem                  -> Passe à l'élément suivant dans l'écran liste
/*    PriorItem                 -> Passe à l'élément précédent dans l'écran liste
/*    ChangeCurrentFormPos      -> Repositionne la form dans le centre de la fenêtre
/*    SetDLLInstance            -> Donne l'instance de la DLL à l'objet TreeView
/*                                 afin de trouver les écrans associés
/*    CustomSelect              -> Lance l'évènement OnCustomSelect de la form
/*    DisplayCustomSelectBtn    -> Permet de déterminer si l'écran possède
/*                                 une fonction de recherche personnalisé de
/*                                 l'élément courant, appellé uniquement par
/*                                 l'objet CPageControl.
/*    GetMenuButton             -> Renvoie l'objet TBitBtn associé à un Node
/*    GetScreenInstanceProc     -> Recherche la fonction d'instanciation d'un écran
/*
/***************************************************************************/
//---------------------------------------------------------------------------
TCallCreateInstance __fastcall CTree::GetScreenInstanceProc(CNodeInfos *nodeinfos)
{
  ASSERT( nodeinfos->InstanceIndex < m_pInstances->Count);
  return (TCallCreateInstance)::GetProcAddress(( HMODULE)m_pInstances->Strings[nodeinfos->InstanceIndex].ToInt(),
                                                ("@" + nodeinfos->ClassName + "@CreateInstance$qp18Classes@TComponent").c_str() );
}
//---------------------------------------------------------------------------
TBitBtn *__fastcall CTree::GetMenuButton(CNodeInfos *nodeinfos)
{
  ASSERT( dynamic_cast<CTree*>( nodeinfos->Node->TreeView));

  TForm       *pForm    = (( CTree*)nodeinfos->Node->TreeView)->GetForm( nodeinfos->TagParent); if (!pForm) return NULL;
  TWinControl *pWinCtrl = dynamic_cast<TWinControl *>( FindControlTag( pForm, nodeinfos->TagMenu)); ASSERT( pWinCtrl);
  TBitBtn     *pBitBtn  = dynamic_cast<TBitBtn *>    ( FindControlTag( pWinCtrl, nodeinfos->Tag ));
  return pBitBtn;
}
//---------------------------------------------------------------------------
void __fastcall CTree::SetInstance( HINSTANCE HInst, CTree *pTree)
{
  m_pInstances->AddObject( IntToStr(( int)HInst), pTree);
}
//---------------------------------------------------------------------------
void __fastcall CTree::DisplayBranche(int Tag)
{
  TTreeNode  *nodeSoon;
  TTreeNode  *nodeSoonAfter;
  CNodeInfos *nodeinfos;
  int         tagParent;

  nodeSoon  = NULL;
  tagParent = GetParentCTree()->FindNode( Tag)->TagParent;
  // Recherche le frère de la branche à insérer
  // et insére le node
  for(int i=0; i<m_NodesInfos->Count; i++) {
    nodeinfos = (CNodeInfos *)m_NodesInfos->Items[i];
    if (nodeinfos->Tag == Tag) {
      if (nodeSoon) {
        if( nodeinfos->TagParent==-1)
          nodeSoonAfter = NULL; // Pas de parent
        else {
          if( nodeinfos->TagBrother!=-1) nodeSoonAfter = GetParentCTree()->FindNode(nodeinfos->TagBrother)->Node;
                                    else nodeSoonAfter = GetParentCTree()->FindNode(nodeinfos->TagParent)->Node->GetNextChild(nodeSoon);
        }
        if (nodeSoonAfter) {
          nodeinfos->Node = GetParentCTree()->Items->Insert(nodeSoonAfter, ConvertText(nodeinfos->Text));
          TAG_NODE(nodeinfos->Node) = nodeinfos->Tag;
          //TAG_NODE_AF( nodeinfos->Node, nodeinfos->Tag);
        } else {
          nodeinfos->Node = GetParentCTree()->Items->Add(nodeSoon, ConvertText(nodeinfos->Text));
          TAG_NODE(nodeinfos->Node) = nodeinfos->Tag;
          //TAG_NODE_AF( nodeinfos->Node, nodeinfos->Tag);
        }
      } else {
        //nodeinfos->Node = Items->AddChild(nodeinfos->TagParent==-1 ? NULL : FindNode(nodeinfos->TagParent)->Node, ConvertText(nodeinfos->Text));
        if( nodeinfos->TagParent==-1) {
          nodeinfos->Node = GetParentCTree()->Items->AddChildFirst( NULL, ConvertText(nodeinfos->Text));
          TAG_NODE(nodeinfos->Node) = nodeinfos->Tag;
        } else {
          if( GetParentCTree()->FindNode( nodeinfos->TagParent)->Node) {
            nodeinfos->Node = GetParentCTree()->Items->AddChildFirst(nodeinfos->TagParent==-1 ? NULL : GetParentCTree()->FindNode(nodeinfos->TagParent)->Node, ConvertText(nodeinfos->Text));
            TAG_NODE(nodeinfos->Node) = nodeinfos->Tag;
          }
        }
      }
      if (IS_CURRENTELEM(nodeinfos->WindowStyle)) SetBoldNode(true, nodeinfos->Node);
      // Mise en place des bitmaps
      SetInternalEnableScreen(nodeinfos->Enabled, nodeinfos->Tag);
      break;
    }
    if ((nodeinfos->TagParent==tagParent) && (nodeinfos->Visible) &&
        (nodeinfos->Mode & nodeinfos->Tree->m_Mask)) nodeSoon=nodeinfos->Node;
  }

  // Insère le fils du node rendu visible
  for(int i=0; i<m_NodesInfos->Count; i++) {
    nodeinfos = (CNodeInfos *)m_NodesInfos->Items[i];
    if (nodeinfos->Visible && (nodeinfos->Mode & nodeinfos->Tree->m_Mask) &&
        IsSoonOf(Tag, nodeinfos->TagParent)) {
      // Affichage du texte dans l'arbre
      if (nodeinfos->TagParent != -1) {
        if( GetParentCTree()->FindNode( nodeinfos->TagParent)->Node!=NULL) {
          if( nodeinfos->TagBrother==-1)
               nodeinfos->Node = GetParentCTree()->Items->AddChild( GetParentCTree()->FindNode( nodeinfos->TagParent )->Node, ConvertText( nodeinfos->Text));
          else nodeinfos->Node = GetParentCTree()->Items->Insert  ( GetParentCTree()->FindNode( nodeinfos->TagBrother)->Node, ConvertText( nodeinfos->Text));
          TAG_NODE(nodeinfos->Node) = nodeinfos->Tag;
          //TAG_NODE_AF(nodeinfos->Node, nodeinfos->Tag);
        }
      } else {
        nodeinfos->Node = GetParentCTree()->Items->Add( NULL, ConvertText(nodeinfos->Text));
        TAG_NODE(nodeinfos->Node) = nodeinfos->Tag;
        //TAG_NODE_AF( nodeinfos->Node, nodeinfos->Tag);
      }
      if (IS_CURRENTELEM(nodeinfos->WindowStyle)) SetBoldNode(true, nodeinfos->Node);
      // Mise en place des bitmaps
      SetInternalEnableScreen(nodeinfos->Enabled, nodeinfos->Tag);
    }
  }
}
//---------------------------------------------------------------------------
void __fastcall CTree::SetTextMenu(const AnsiString &strCaption, CNodeInfos *nodeinfos)
{
  TBitBtn *pButton;

  if (nodeinfos->Text==strCaption) return;

  nodeinfos->Text = strCaption;       // Modification des extras-données
  if (!nodeinfos->Node) return;       // Si node non visible

  nodeinfos->Node->Text = strCaption; // Modification du text de la TreeView
  if ((pButton=GetMenuButton(nodeinfos)) != NULL) {
    AnsiString strBtnCaption;
    CreateButtonCaption( nodeinfos, strBtnCaption);
    pButton->Caption = strBtnCaption;
  }
  // Redessine la barre d'onglet
  if( m_pPageCtrl) m_pPageCtrl->Draw();
}
//---------------------------------------------------------------------------
int __fastcall CTree::SelectedRealAbsoluteIndex()
{
  for(int i=Items->Count-1; i>=0; i--)
    if (Items->Item[i]==Selected) return i;
  return -1;
}
//---------------------------------------------------------------------------
bool __fastcall CTree::IsSoonOf(int nTag, int nTagParent)
{
  while (nTagParent != -1) {
    if (nTag==nTagParent) return true;
    nTagParent = GetParentCTree()->FindNode( nTagParent)->TagParent;
  }
  return false;
}
//---------------------------------------------------------------------------
TControl *__fastcall CTree::FindControlTag(TWinControl *pWCtrl, int nTag)
{
  TControl *pControl;
  if (!pWCtrl)
     return NULL;
  // Recherche parmi tous les contrôles contenus dans un contrôle
  // fenêtré celui dont son nTag vaut le numéro demandé
  for( int i=pWCtrl->ControlCount-1; i>=0; i--) {
    pControl = pWCtrl->Controls[i];
    if ( pControl->Tag==nTag) return pControl;
  }
  for( int i=pWCtrl->ControlCount-1; i>=0; i--) {
    pControl = pWCtrl->Controls[i];
    if ( dynamic_cast< TWinControl*>( pControl)) {
      pControl = FindControlTag(( TWinControl*)pControl, nTag);
      if ( pControl) return pControl;
    }
  }
  return NULL;
}
//---------------------------------------------------------------------------
CEICForm *__fastcall CTree::GetParentForm(int nIndex)
{
  ASSERT(( nIndex>=0) && ( nIndex<m_pScrOpen->Count));
  return nIndex==0 ? NULL : ( CEICForm*)m_pScrOpen->Items[nIndex-1];
/*
  if (nIndex==0) return NULL;
  return (CEICForm *)m_pScrOpen->Items[nIndex-1];
*/
}
//---------------------------------------------------------------------------
void __fastcall CTree::SetEnableAllBranche(TTreeNode *Node)
{
  CNodeInfos *nodeinfos;

  for(int i=0; i<Node->Count; i++) {
    nodeinfos = FindNode(Node->Item[i]);
    if (!nodeinfos->MenuCreate) SetInternalEnableScreen(true, nodeinfos->Tag);
  }
}
//---------------------------------------------------------------------------
void __fastcall CTree::DisableSystemButtons()
{
  TTreeNode  *pNode, *pSelectedNode;
  CNodeInfos *nodeinfos;
  bool        bEnabled;

  // Permet de Enabler/Disabler les boutons de changement d'écran
  // et du passage direct au père
  pSelectedNode = GetParentCTree()->Selected;
  if ( !pSelectedNode) return;
  SetButtonAction( BA_PARENT_RETURN, pSelectedNode->Parent!=NULL);

  pNode    = pSelectedNode->Parent->GetPrevChild( pSelectedNode);
  bEnabled = false;
  if( pNode) {
    do {
      nodeinfos = GetParentCTree()->FindNode( pNode);
      if( nodeinfos->Enabled && !IS_CURRENTELEM( nodeinfos->WindowStyle)) {
        bEnabled = true;
        break;
      }
      pNode = pSelectedNode->Parent->GetPrevChild( pNode);
    } while( pNode);
  }
  SetButtonAction( BA_PRIOR, bEnabled);

  pNode = pSelectedNode->Parent->GetNextChild( pSelectedNode);
  bEnabled = false;
  if( pNode) {
    do {
      nodeinfos = GetParentCTree()->FindNode( pNode);
      if( nodeinfos->Enabled && !IS_CURRENTELEM( nodeinfos->WindowStyle)) {
        bEnabled = true;
        break;
      }
      pNode = pSelectedNode->Parent->GetNextChild( pNode);
    } while( pNode);
  }
  SetButtonAction( BA_NEXT, bEnabled);
}
//---------------------------------------------------------------------------
TTreeNode *__fastcall CTree::FindCommonParent(TTreeNode *oldNode, TTreeNode *newNode, bool &error)
{
  TTreeNode *node_o, *node_n, *node_error;
  CEICForm  *pForm;
  bool       retclosequery  = true;
  int        i, level_error =   -1;

  if (oldNode==NULL) { error=false; return NULL; }

  // Recherche s'il est impossible de quitter une partie de la branche
  for(i=m_pScrOpen->Count-1,node_o=oldNode; i>=0; i--,node_o=node_o->Parent) {
    pForm = (CEICForm *)m_pScrOpen->Items[i];
    if (pForm) {
      try { retclosequery = pForm->CloseQuery(); } catch( EAbort &e) { retclosequery = false; }
    }
      // if (pForm->OnCloseQuery) pForm->OnCloseQuery(this, retclosequery);
    if( !retclosequery) {
      level_error = node_o->Level;
      node_error  = node_o;
      if( pForm) m_hwndFocusedAfterError = ::GetFocus();
            else m_hwndFocusedAfterError = NULL;
      break;
    }
  }

  // Recherche la branche commune
  node_n = newNode;
  while (node_n != NULL) {
    node_o = oldNode;
    while (node_o != NULL) {
      if (node_o == node_n) goto find_common;
      node_o = node_o->Parent;
    }
    node_n = node_n->Parent;
  }

  if (level_error!=-1) { error=true; return (node_error); }
  else { error=false; return (NULL); }

find_common:
  if (node_o->Level <= level_error) { error=true; return (node_error); }
  error = false; return (node_n);
}
//---------------------------------------------------------------------------
void __fastcall CTree::ChangeCurrentElement( CEICForm *pForm)
{
  CNodeInfos *nodeinfos;

  if( pForm->ScreenTag==0) return;
  // Recherche dans tous les écrans qui sont de type écran liste
  while( pForm!=NULL) {
    nodeinfos = FindNode( SCREEN_TAG( pForm));
    if( IS_LISTE( nodeinfos->WindowStyle)) InitScreenMenu( pForm, nodeinfos);
    pForm     = GetParentForm( pForm);
  }
}
//---------------------------------------------------------------------------
AnsiString __fastcall CTree::ConvertText(const AnsiString &strCaption)
{
  int nPosTab = strCaption.Pos( "\\t");
  return ( nPosTab==0 ? strCaption : strCaption.SubString( 1, nPosTab-1));
}
//---------------------------------------------------------------------------
void __fastcall CTree::NextItem()
{
  TDBGrid *pGrid;
  CEICForm *form;
  // Sélectionne l'élément suivant
  try {
    if ( (pGrid=GetDBList(m_pfrmCurrent))==NULL ) return;
    ASSERT(pGrid);
    ASSERT(pGrid->DataSource);
    ASSERT(pGrid->DataSource->DataSet);

    form = GetCurrentForm();
    if (!form->CloseQuery())
      Abort();

    ::SendMessage( m_pPageCtrl->Handle, WM_SETREDRAW, FALSE, 0);
    bool       bFind  = false;
    AnsiString strBookmark( pGrid->DataSource->DataSet->Bookmark);
    do {
      pGrid->DataSource->DataSet->Next();
      if( IS_ENABLED( FindNode( Selected))) { bFind = true; break; }
    } while( !pGrid->DataSource->DataSet->Eof);
    if( !bFind) pGrid->DataSource->DataSet->Bookmark = strBookmark;
    ::SendMessage( m_pPageCtrl->Handle, WM_SETREDRAW, TRUE, 0);
    ::RedrawWindow( m_pPageCtrl->Handle, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_INTERNALPAINT);

  } catch (EAbort &e) {//Une table a certainement abandonné des modifs
  } catch (Exception &e) {
    throw EUser( TAG(44), e);
  }
}
//---------------------------------------------------------------------------
void __fastcall CTree::PriorItem()
{
  TDBGrid *pGrid;
  CEICForm *form;
  // Sélectionne l'élement précedent
  try {
    if ( (pGrid=GetDBList(m_pfrmCurrent))==NULL ) return;
    ASSERT(pGrid);
    ASSERT(pGrid->DataSource);
    ASSERT(pGrid->DataSource->DataSet);

    form = GetCurrentForm();
    if (!form->CloseQuery())
      Abort();

    ::SendMessage( m_pPageCtrl->Handle, WM_SETREDRAW, FALSE, 0);
    bool       bFind  = false;
    AnsiString strBookmark( pGrid->DataSource->DataSet->Bookmark);
    do {
      pGrid->DataSource->DataSet->Prior();
      if( IS_ENABLED( FindNode( Selected))) { bFind = true; break; }
    } while( !pGrid->DataSource->DataSet->Bof);
    if( !bFind) pGrid->DataSource->DataSet->Bookmark = strBookmark;
    ::SendMessage( m_pPageCtrl->Handle, WM_SETREDRAW, TRUE, 0);
    ::RedrawWindow( m_pPageCtrl->Handle, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN | RDW_INTERNALPAINT);

  } catch (EAbort &e) {//Une table a certainement abandonné des modifs
  } catch (Exception &e) {
    throw EUser( TAG(46), e);
  }
}
//---------------------------------------------------------------------------
void __fastcall CTree::ChangeCurrentFormPos()
{
  if ( !m_pfrmCurrent) return;

  if ( m_bResizeable) {
    // Toujours maximized
    m_pfrmCurrent->Left   = m_pPageCtrl->GetClientLeft();
    m_pfrmCurrent->Top    = m_pPageCtrl->GetClientTop();
    m_pfrmCurrent->Height = m_pPageCtrl->GetClientHeight();
    m_pfrmCurrent->Width  = m_pPageCtrl->GetClientWidth();
    m_pfrmCurrent->RecentrerControls();
  } else {
    // Timbre poste
    int nLeft   = m_pPageCtrl->GetClientLeft();
    int nTop    = m_pPageCtrl->GetClientTop();
    int nHeight = m_pPageCtrl->GetClientHeight();
    int nWidth  = m_pPageCtrl->GetClientWidth();
    if ( nWidth >m_nWidthScr ) { nLeft =        (nWidth -m_nWidthScr )/2; nWidth  = m_nWidthScr;  }
    if ( nHeight>m_nHeightScr) { nTop  = nTop + (nHeight-m_nHeightScr)/2; nHeight = m_nHeightScr; }
    if ( nLeft  <m_pPageCtrl->GetClientLeft()) nLeft = m_pPageCtrl->GetClientLeft();
    if ( nTop   <m_pPageCtrl->GetClientTop ()) nTop  = m_pPageCtrl->GetClientTop();
    m_pfrmCurrent->Left   = nLeft;
    m_pfrmCurrent->Top    = nTop;
    m_pfrmCurrent->Height = nHeight;
    m_pfrmCurrent->Width  = nWidth;
  }
}
//---------------------------------------------------------------------------
bool __fastcall CTree::DisplayCustomSelectBtn()
{
  CEICForm   *pForm = m_pfrmCurrent;
  CNodeInfos *nodeinfos;

  while (pForm != NULL) {
    nodeinfos = FindNode( SCREEN_TAG( pForm));
    if (IS_LISTE(nodeinfos->WindowStyle) /*&& (nodeinfos->KeyField!=EmptyStr)*/) break;
    pForm = GetParentForm(pForm);
  }

  if (!pForm) return false;
  return (pForm->OnCustomSelect != NULL);
}
//---------------------------------------------------------------------------
void __fastcall CTree::CustomSelect()
{
  CEICForm   *pForm = m_pfrmCurrent;
  CNodeInfos *nodeinfos;

  while (pForm != NULL) {
    nodeinfos = FindNode( SCREEN_TAG( pForm));
    if (IS_LISTE(nodeinfos->WindowStyle) /*&& (nodeinfos->KeyField!=EmptyStr)*/) break;
    pForm = GetParentForm(pForm);
  }

  ASSERT( pForm);
  if (pForm->OnCustomSelect) pForm->OnCustomSelect(this);
}
//---------------------------------------------------------------------------
/***************************************************************************/
/*
/*  Fonctions permettant de séléctionner un autre écran soit directement
/*  soit le suivant ou le précédent
/*
/*  Fonctions:
/*  ----------
/*    SetSelectedMenuInternal -> Sélectionne un écran spécifique donné par son Tag
/*    Prior                   -> Sélectionne l'écran précédent
/*    Next                    -> Sélectionne l'écran suivant
/*    Return                  -> Sélectionne l'écran pères
/*
/***************************************************************************/
//---------------------------------------------------------------------------
void __fastcall CTree::SetSelectedMenuInternal(int nTagMenu)
{
  TTreeNode *Node = FindNode( nTagMenu)->Node;
  Selected = Node ? Node : Selected;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall CTree::Prior()
{
  TTreeNode *pCurNode;
  TTreeNode *pPrevNode = Selected;

  do {
    pCurNode  = pPrevNode;
    pPrevNode = pCurNode->Parent->GetPrevChild( pCurNode);
    if (pPrevNode == NULL)
      {
        if (pCurNode->Parent->GetNextChild(pCurNode) == NULL)
          PriorItem();          //On n'a pas d'écran suivant et précédent, on va essayer de se déplacer dans la liste
        return;
      }
//    if( pPrevNode==NULL) return;
    if( IS_CURRENTELEM( FindNode( pPrevNode)->WindowStyle)) continue;
    //if (FindNode(PrevNode)->Enabled) { Selected=PrevNode; return; }
    if( IS_ENABLED( FindNode( pPrevNode))) { Selected=pPrevNode; return; }
  } while( true);
}
//---------------------------------------------------------------------------
void __fastcall CTree::Next()
{
  TTreeNode *pCurNode;
  TTreeNode *pNextNode = Selected;

  do {
    pCurNode  = pNextNode;
    pNextNode = pCurNode->Parent->GetNextChild( pCurNode);
    if (pNextNode == NULL)
      {
        if (pCurNode->Parent->GetPrevChild(pCurNode) == NULL)
          NextItem();          //On n'a pas d'écran suivant et précédent, on va essayer de se déplacer dans la liste
        return;
      }
//    if( pNextNode==NULL) return;
    if( IS_CURRENTELEM( FindNode( pNextNode)->WindowStyle)) continue;
    //if (FindNode(NextNode)->Enabled) { Selected=NextNode; return; }
    if( IS_ENABLED( FindNode( pNextNode))) { Selected=pNextNode; return; }
  } while( true);
}
//---------------------------------------------------------------------------
void __fastcall CTree::Return()
{
  if (Selected->Parent != NULL) Selected = Selected->Parent;
}
//---------------------------------------------------------------------------
/***************************************************************************/
/*
/*  Fonctions utilisateur permettant de modifier les états des écrans
/*
/*  Fonctions:
/*  ----------
/*    SetEnableScreen   -> Enable ou disable un écran
/*    SetVisibleScreen  -> Rend visible ou cache un écran
/*    SetSelectedScreen -> Séléectionne un écran spécifique
/*    GetEnableScreen   -> Renvoie l'état d'un écran
/*    GetVisibleScreen  -> Détermine si l'état est visible ou non
/*    GetSelectedScreen -> Renvoie l'écran actuellement sélectionné
/*    GetForm           -> Renvoie la form d'un écran si celui-ci
/*                         est chargé
/*    GetParentForm     -> Renvoie le parent d'une form si elle est chargée
/*    GetDBList         -> Renvoie le DBGrid d'un menu liste
/*    SetTextScreen     -> Change le texte d'un écran
/*    GetTextScreen     -> Renvoie le texte d'un écran (sans le texte après le \t)
/*    GetTextScreenComplet -> Renvoie le texte complet d'un écran (avec le texte après le \t)
/*    GetCurrentForm    -> Renvoie la form en cours
/*    SetComponentDataSource -> Affecte un DataSource aux composants
/*                              d'un certain Tag
/*    SetBoldNode       -> Met un node en caractères gras
/*    ReplaceRessource  -> Remplace la ressource d'un écran par celle
/*                         d'un autre écran
/*    InsertAssistant   -> Insère un assistant dans le menu d'un autre
/*                         assistant
/*    GetNodeExtraInfos -> Renvoie toutes les données d'un node
/*                         (Utilisable quand mode debug)
/*
/***************************************************************************/
//---------------------------------------------------------------------------
void __fastcall CTree::ExpandNode( int nTag, bool bRecurse)
{
  ASSERT( FindNode( nTag)->Node);
  FindNode( nTag)->Node->Expand( bRecurse);
}
//---------------------------------------------------------------------------
void __fastcall CTree::CollapseNode( CNodeInfos *nodeinfos, bool bRecurse)
{
  m_bCanCollapse = true;
  ASSERT( nodeinfos->Node);
  nodeinfos->Node->Collapse( bRecurse);
  m_bCanCollapse = false;
}
//---------------------------------------------------------------------------
void __fastcall CTree::CollapseNode( int nTag, bool bRecurse)
{
  CollapseNode( FindNode( nTag), bRecurse);
}
//---------------------------------------------------------------------------
void __fastcall CTree::ExitAssistant()
{
  ASSERT( dynamic_cast< TForm*>( Parent));
  m_bExitAss = true;
  ::PostMessage( Parent->Handle, WM_CLOSE, 0, 0);
}
//---------------------------------------------------------------------------
void __fastcall CTree::SetInternalEnableScreen( bool bEnabled, int nTag)
{
  CNodeInfos *nodeinfos = GetParentCTree()->FindNode(nTag);
  TBitBtn    *pButton;

  if (IS_CURRENTELEM(nodeinfos->WindowStyle)) return;

       nodeinfos->Enabled= bEnabled;
  if (!nodeinfos->Visible || !nodeinfos->Node) return;

  const int *BMP = IS_ENABLED( nodeinfos) ? EnableBMP : DisableBMP;
  if( m_bUseCustomIcons) {
    nodeinfos->Node->ImageIndex    = BMP[ICON( this, nodeinfos)];
    nodeinfos->Node->SelectedIndex = BMP[ICON( this, nodeinfos)];
  } else {
    if (nodeinfos->HaveList) {
      nodeinfos->Node->ImageIndex    = BMP[nodeinfos->WindowStyle];
      nodeinfos->Node->SelectedIndex = BMP[nodeinfos->WindowStyle];
    } else {
      nodeinfos->Node->ImageIndex    = BMP[SCR_MENU];
      nodeinfos->Node->SelectedIndex = BMP[SCR_MENU];
    }
  }
  if( !IS_ENABLED( nodeinfos)) CollapseNode( nodeinfos, true);

  DisableSystemButtons();
  Invalidate();

  // Enable ou Disable le bouton dans le menu
  if ((pButton=GetMenuButton(nodeinfos)) != NULL) pButton->Enabled = IS_ENABLED( nodeinfos);
}
//---------------------------------------------------------------------------
void __fastcall CTree::SetEnableScreen(bool bEnabled, int nTag)
{
  CNodeInfos *nodeinfos = FindNode( nTag);
  if( nodeinfos->Enabled==bEnabled) return;
  SetInternalEnableScreen( bEnabled, nodeinfos->Tag);
}
//---------------------------------------------------------------------------
void __fastcall CTree::SetVisibleScreen(bool bVisible, int nTag)
{
  CNodeInfos *nodeinfos   = FindNode(nTag);
  TTreeNode  *pNodeParent = NULL;

  if (nodeinfos->Visible==bVisible) return;
      nodeinfos->Visible =bVisible;

  // On quitte la fonction, si l'arbre n'est pas encore entièrement initialisé
  if( !GetParentCTree()->Selected) return;

  switch( bVisible) {
    case true  : if( nodeinfos->Node==NULL) DisplayBranche( nodeinfos->Tag);
                 if( nodeinfos->Node!=NULL) pNodeParent = nodeinfos->Node->Parent;
                 break;
    case false : if( nodeinfos->Node!=NULL) {
                   pNodeParent = nodeinfos->Node->Parent;
                   GetParentCTree()->Items->Delete( nodeinfos->Node);
                 }
                 break;
  }
  DisableSystemButtons();

  CForm *pForm;
  if ((pForm=GetParentCTree()->GetForm(nodeinfos->TagParent))==NULL) return;
  TWinControl *panel = dynamic_cast<TWinControl *>(FindControlTag(pForm, nodeinfos->TagMenu));
  if( panel) {
    for( int i=panel->ControlCount-1; i>=0; i--) {
    	if( dynamic_cast<TBitBtn*>( panel->Controls[i])) delete dynamic_cast<TBitBtn*>( panel->Controls[i]);
    }
  }

	pForm->ScreenTag &= 0xFFFDFFFF;
  if( pNodeParent) {
  	nodeinfos         = GetParentCTree()->FindNode( pNodeParent);
	  if ( nodeinfos->Tag == SCREEN_TAG( GetParentCTree()->m_pfrmCurrent))
	    DisplayButtons(pNodeParent, nodeinfos);
  }
}
//---------------------------------------------------------------------------
void __fastcall CTree::SetSelectedScreen(int nTag, bool bImmediately /* = false */)
{
  if (bImmediately) SetSelectedMenuInternal( nTag);
			   else ::PostMessage(Handle, WM_SETSELMENU, 0, nTag);
}
//---------------------------------------------------------------------------
bool __fastcall CTree::GetEnableScreen(int nTag)
{
  return FindNode( nTag)->Enabled;
}
//---------------------------------------------------------------------------
bool __fastcall CTree::GetVisibleScreen(int nTag)
{
  CNodeInfos *nodeinfos = FindNode( nTag);
  return nodeinfos->Visible && nodeinfos->Node;
}
//---------------------------------------------------------------------------
int __fastcall CTree::GetSelectedScreen(void)
{
  int nTag = GetLoadingScreen();
  if( nTag!=-1) return nTag;

  if( !Selected) {
    // On est dans un CTree qui a été inséré dans un autre.
    // On est obligé de scruter tous les noeuds afin de trouvé celui qui est sélectionné
    for( int i=FirstNodeTag; i<=LastNodeTag; i++)
      if( FindNode( i)->Node && FindNode( i)->Node->Selected) return i;
    ASSERT( false);
    return -1;
  }
  // Recherche de l'écran sélectionné dans un CTree principal
  return FindNode( Selected)->Tag;
}
//---------------------------------------------------------------------------
int __fastcall CTree::GetLoadingScreen()
{
  return m_nLoadingTag;
}
//---------------------------------------------------------------------------
CEICForm *__fastcall CTree::GetForm(int nTag)
{
  CEICForm *pForm;

  // Recherche dans la liste des écrans actuellement chargé
  // celui qui possède le tag voulu
  for(int i=m_pScrOpen->Count-1; i>=0; i--) {
    pForm = (CEICForm *)m_pScrOpen->Items[i];
    if ( SCREEN_TAG( pForm)==nTag) return pForm;
  }
  return NULL;
}
//---------------------------------------------------------------------------
CEICForm *__fastcall CTree::GetParentForm(CEICForm *Form)
{
  int nIndex = -1;

  for(int i=m_pScrOpen->Count-1; i>=0; i--)
    if (m_pScrOpen->Items[i]==Form) { nIndex=i; break; }

  return (nIndex==-1 ? NULL : GetParentForm(nIndex));
}
//---------------------------------------------------------------------------
/*TDBGrid *__fastcall CTree::GetCurrentDBList( CEICForm *pForm)
{
  TDBGrid *pGrid = NULL;

  for( int i=pForm->ControlCount-1; i>=0; i--) {
    if( dynamic_cast<TCustomDBGrid*>( pForm->Controls[i])) pGrid = ( TDBGrid*)pForm->Controls[i];
  }

  return pGrid;
}*/
TDBGrid *__fastcall CTree::GetCurrentDBList( TWinControl *pWndCtrl)
{
  TDBGrid *pGrid = NULL;

  for( int i=pWndCtrl->ControlCount-1; i>=0; i--) {
         if( dynamic_cast<TCustomDBGrid*>( pWndCtrl->Controls[i])) pGrid = ( TDBGrid*)pWndCtrl->Controls[i];
    else if( dynamic_cast<TWinControl  *>( pWndCtrl->Controls[i])) pGrid = GetCurrentDBList(( TWinControl*)pWndCtrl->Controls[i]);
    if( pGrid) break;
  }

  return pGrid;
}
//---------------------------------------------------------------------------
TDBGrid *__fastcall FindTDBGrid( TWinControl *pCtrl)
{
  if( !pCtrl) return NULL;

  TDBGrid *pGrid = NULL;
  for( int i=pCtrl->ControlCount-1; i>=0; i--) {
    if( dynamic_cast<TCustomDBGrid*>( pCtrl->Controls[i])) return ( TDBGrid*)pCtrl->Controls[i];
    pGrid = FindTDBGrid( dynamic_cast<TWinControl*>( pCtrl->Controls[i]));
    if( pGrid) return pGrid;
  }
  return pGrid;
}
//---------------------------------------------------------------------------
TDBGrid *__fastcall CTree::GetDBList( CEICForm *pForm /* = NULL */, CEICForm **pFormList /* = NULL */)
{
  if( !pForm) pForm = m_pfrmCurrent;
  if( !pForm) return NULL;

  CNodeInfos *nodeinfos;
  TDBGrid    *pGrid       = NULL;
  int         nRecurs     = 0;
  bool        bIsScrListe = IS_LISTE( FindNode( SCREEN_TAG( pForm))->WindowStyle);

  do {
    nodeinfos = FindNode( SCREEN_TAG( pForm));
    if( IS_LISTE( nodeinfos->WindowStyle)) {
//      for( int i=pForm->ControlCount-1; i>=0; i--)
//        if( dynamic_cast<TCustomDBGrid*>( pForm->Controls[i])) { pGrid = ( TDBGrid*)pForm->Controls[i]; nRecurs++; }
      if( pFormList) *pFormList = pForm;
      if(( pGrid = FindTDBGrid( pForm))!=NULL) nRecurs++;

      if(  bIsScrListe && ( nRecurs==2)) break;
      if( !bIsScrListe) break;
    }
  } while(( pForm=GetParentForm( pForm))!=NULL);

  return pGrid;




/*
  TComponent *curComponent;
  TDBGrid    *pGrid = NULL;
  if (!Form)  Form  = m_pfrmCurrent;

  do {
    for(int i=Form->ComponentCount-1; i>=0; i--) {
      curComponent = Form->Components[i];
      if (dynamic_cast<TCustomDBGrid *>(curComponent)) {
        if (pGrid) { if (pGrid->Name!=LISTENAME) pGrid = (TDBGrid *)curComponent; }
        else pGrid = (TDBGrid *)curComponent;
      }
    }
  } while ((Form=GetParentForm(Form))!=NULL);

  return pGrid;
*/
}
//---------------------------------------------------------------------------
void __fastcall CTree::SetTextScreen(const AnsiString &strCaption, int nTag)
{
  SetTextMenu(strCaption, FindNode( nTag));
}
//---------------------------------------------------------------------------
AnsiString __fastcall CTree::GetTextScreen(int nTag)
{
  int Position;
  AnsiString TextComplet = FindNode( nTag)->Text;
  Position = TextComplet.Pos("\\t");
  if (Position)
    TextComplet.Delete(Position,TextComplet.Length());
  return TextComplet;
}
//---------------------------------------------------------------------------
AnsiString __fastcall CTree::GetTextScreenComplet(int nTag)
{
  return FindNode( nTag)->Text;
}
//---------------------------------------------------------------------------
char __fastcall CTree::GetLevelScreen( int nTag)
{
  return FindNode( nTag)->Level;
}
//---------------------------------------------------------------------------
void __fastcall CTree::SetLevelScreen( int nTag, char cLevel)
{
  TBitBtn    *pButton;
  CNodeInfos *nodeinfos = FindNode( nTag);

  if( nodeinfos->Level==cLevel) return;

  nodeinfos->Level = cLevel;     // Modification des extras-données
  if( !nodeinfos->Node) return;  // Si node non visible

  if(( pButton=GetMenuButton( nodeinfos)) != NULL) {
    AnsiString strBtnCaption;
    CreateButtonCaption( nodeinfos, strBtnCaption);
    pButton->Caption = strBtnCaption;
  }
  // Redessine la barre d'onglet
  if( m_pPageCtrl) m_pPageCtrl->Draw();
}
//---------------------------------------------------------------------------
CEICForm *__fastcall CTree::GetCurrentForm()
{
  return m_pfrmCurrent;
}
//---------------------------------------------------------------------------
void __fastcall CTree::SetComponentDataSource(TDataSource *pDataSource, int nTag, CEICForm *pForm /* = NULL */)
{
  if (!pForm) pForm = m_pfrmCurrent;

  for(int i=pForm->ComponentCount-1; i>=0; i--) {
    TComponent *CurComponent = pForm->Components[i];
    if (CurComponent->Tag != nTag) continue;

         if (dynamic_cast<TCustomDBGrid     *>(CurComponent)) dynamic_cast<TDBGrid           *>(CurComponent)->DataSource = pDataSource;
    else if (dynamic_cast<TDBNavigator      *>(CurComponent)) dynamic_cast<TDBNavigator      *>(CurComponent)->DataSource = pDataSource;
    else if (dynamic_cast<TDBText           *>(CurComponent)) dynamic_cast<TDBText           *>(CurComponent)->DataSource = pDataSource;
    else if (dynamic_cast<TDBEdit           *>(CurComponent)) dynamic_cast<TDBEdit           *>(CurComponent)->DataSource = pDataSource;
    else if (dynamic_cast<TDBMemo           *>(CurComponent)) dynamic_cast<TDBMemo           *>(CurComponent)->DataSource = pDataSource;
    else if (dynamic_cast<TDBImage          *>(CurComponent)) dynamic_cast<TDBImage          *>(CurComponent)->DataSource = pDataSource;
    else if (dynamic_cast<TDBListBox        *>(CurComponent)) dynamic_cast<TDBListBox        *>(CurComponent)->DataSource = pDataSource;
    else if (dynamic_cast<TDBComboBox       *>(CurComponent)) dynamic_cast<TDBComboBox       *>(CurComponent)->DataSource = pDataSource;
    else if (dynamic_cast<TDBCheckBox       *>(CurComponent)) dynamic_cast<TDBCheckBox       *>(CurComponent)->DataSource = pDataSource;
    else if (dynamic_cast<TDBRadioGroup     *>(CurComponent)) dynamic_cast<TDBRadioGroup     *>(CurComponent)->DataSource = pDataSource;
    else if (dynamic_cast<TDBLookupListBox  *>(CurComponent)) dynamic_cast<TDBLookupListBox  *>(CurComponent)->DataSource = pDataSource;
    else if (dynamic_cast<TDBLookupComboBox *>(CurComponent)) dynamic_cast<TDBLookupComboBox *>(CurComponent)->DataSource = pDataSource;
    else if (dynamic_cast<TDBRichEdit       *>(CurComponent)) dynamic_cast<TDBRichEdit       *>(CurComponent)->DataSource = pDataSource;
    else if (dynamic_cast<TDBCtrlGrid       *>(CurComponent)) dynamic_cast<TDBCtrlGrid       *>(CurComponent)->DataSource = pDataSource;
  }
}
//---------------------------------------------------------------------------
void __fastcall CTree::SetBoldNode( bool bBold, TTreeNode *Node)
{
  TV_ITEM pItem;

  if( !Node) return;

  pItem.mask      = TVIF_STATE;
  pItem.hItem     = Node->ItemId;
  pItem.state     = bBold ? TVIS_BOLD : 0;
  pItem.stateMask = TVIS_BOLD;
  TreeView_SetItem( Handle, &pItem);
}
//---------------------------------------------------------------------------
void __fastcall CTree::ReplaceRessource( int nTagDst, int nTagSrc)
{
  FindNode( nTagDst)->ClassName = FindNode( nTagSrc)->ClassName;
}
//---------------------------------------------------------------------------
int __fastcall CTree::InsertAssistant( int nTag, int nTagBrother, CTree *pAssistant)
{
  CNodeInfos *nodeinfos;
  int         nBaseTag;
  int         nBaseInstanceIndex;

  ASSERT((( nTag       >=1) && ( nTag       <=m_NodesInfos->Count)) || ( nTag==-1));
  ASSERT((( nTagBrother>=1) && ( nTagBrother<=m_NodesInfos->Count)) || ( nTagBrother==-1));

  // Efface le lien avec le TreeView et affecte le nouveau numéro de Tag
  nBaseTag           = m_NodesInfos->Count;
  nBaseInstanceIndex = m_pInstances->Count;
  for( int i=0; i<pAssistant->m_NodesInfos->Count; i++) {
    nodeinfos = ( CNodeInfos *)pAssistant->m_NodesInfos->Items[i];
    nodeinfos->Tag           += nBaseTag;
    nodeinfos->InstanceIndex += nBaseInstanceIndex;
    if( nodeinfos->TagParent==-1) {
      nodeinfos->TagParent  = nTagBrother!=-1 ? FindNode( nTagBrother)->TagParent : nTag;
      nodeinfos->TagBrother = nTagBrother;
      /*nodeinfos->TagParent  = nTag;
      nodeinfos->TagBrother = nTagBrother;*/
    } else {
      nodeinfos->TagParent  = nodeinfos->TagParent + nBaseTag;
      if( nodeinfos->TagBrother!=-1)
          nodeinfos->TagBrother = nodeinfos->TagBrother + nBaseTag;
    }
    nodeinfos->Node = NULL;
    m_NodesInfos->Add( nodeinfos); // Ajout à la liste de l'assistant père
  }
  // Ajoute les instances des DLLs des assistants dans l'insertion
  for( int i=0; i<pAssistant->m_pInstances->Count;i++) SetInstance(( HINSTANCE)pAssistant->m_pInstances->Strings[i].ToInt(), ( CTree*)pAssistant->m_pInstances->Objects[i]);

  if( Selected) {
    for( int i=FirstNodeTag; i<=LastNodeTag; i++) {
      nodeinfos = FindNode( i);
      if(((( nTag!=-1) && ( nodeinfos->TagParent==nTag)) ||
          (( nTag==-1) && ( nodeinfos->TagBrother==nTagBrother))) && nodeinfos->Visible) {
        nodeinfos->Visible = false;
        SetVisibleScreen( true, i);
      }
    }
  }

  pAssistant->m_pPushInCTree = this;

  return nBaseInstanceIndex;
}
//---------------------------------------------------------------------------
void __fastcall CTree::DeleteAssistant( int nTag, int nIndex)
{
  CNodeInfos *nodeinfos;

  nIndex += FindNode( FirstNodeTag)->InstanceIndex;
  if( Selected) {
    // Supprime l'assistant de l'arbre
    for( int i=FirstNodeTag; i<=LastNodeTag; i++) {
      nodeinfos = FindNode( i);
      if(( nodeinfos->TagParent==nTag) && ( nodeinfos->InstanceIndex>=nIndex))
        SetVisibleScreen( false, i);
    }
  }

  // Supprime les références dans la liste
  for( int i=LastNodeTag; i>=FirstNodeTag; i--)
    if( FindNode( i)->InstanceIndex>=nIndex) m_NodesInfos->Delete( i-1);

  for( int i=m_pInstances->Count-1; i>=nIndex; i--) m_pInstances->Delete( i);
}
//---------------------------------------------------------------------------
CNodeInfos *__fastcall CTree::GetNodeExtraInfos(int Tag)
{
  return FindNode(Tag);
}
//---------------------------------------------------------------------------
int __fastcall CTree::GetFirstNode()
{
  return 1;
}
//---------------------------------------------------------------------------
int __fastcall CTree::GetLastNode()
{
  return m_NodesInfos->Count;
}
//---------------------------------------------------------------------------
int __fastcall CTree::GetFirstChild( int nTagParent)
{
  for( int i=FirstNodeTag; i<=LastNodeTag; i++)
    if( FindNode( i)->TagParent==nTagParent) return i;

  return 0;
}
//---------------------------------------------------------------------------
int __fastcall CTree::GetNextChild( int nTagParent, int nTagChild)
{
  bool        bFindChild = false;
  CNodeInfos *nodeinfos;

  for( int i=FirstNodeTag; i<=LastNodeTag; i++) {
    nodeinfos = FindNode( i);
         if(( nodeinfos->TagParent==nTagParent) && ( nodeinfos->Tag==nTagChild)) bFindChild = true;
    else if(( nodeinfos->TagParent==nTagParent) && bFindChild) return nodeinfos->Tag;
  }

  return 0;
}
//---------------------------------------------------------------------------
/***************************************************************************/
/*
/*  Fonctions utilisés lors du chargement d'un écran
/*
/*  Fonctions:
/*  ----------
/*    DisplayButtons -> Affiche les écrans fils dans le cas d'un
/*                      écran de menu
/*    CloseForm      -> Fonction qui se charge de fermer une form
/*                      en appelant tous les évènements nécessaires
/*    LoadScreen     -> Charge la ressource d'un écran et l'initalise
/*    UnLoadScreens  -> Décharge tous les écrans
/*    InitScreenMenu -> Initialisation d'un écran menu
/*    InitScreen     -> Initialisation des écrans (appel les initialisations
/*                      particulières en fonction des écrans
/*    ChangeScreen   -> Fonction principale qui permet d'afficher
/*                      un écran
/*
/***************************************************************************/
//---------------------------------------------------------------------------
void __fastcall CTree::CreateButtonCaption( CNodeInfos *nodeinfos, AnsiString &strCaption)
{
  strCaption    = " &  -   " + ConvertText( nodeinfos->Text);
  strCaption[3] = nodeinfos->Level>25 ? ( char)( '0' + ( nodeinfos->Level-25)) : ( char)( 'A' + nodeinfos->Level);
}
//---------------------------------------------------------------------------
void __fastcall CTree::DisplayButtons(TTreeNode *Node, CNodeInfos *nodeinfos)
{
  class TGroupBoxCaption : public TCustomGroupBox {
      public    :  __fastcall TGroupBoxCaption( TComponent *pOwner) : TCustomGroupBox( pOwner) {};
    __published :  __property Caption;
  };

  // Mise en place des boutons dans le cas d'un écran menu
  CNodeInfos *childnodeinfos;
  TControl   *parentctrl;
  TBitBtn    *btnMenu;
  int         BtnByTheme[10];
  int         BtnCountTheme[10];
  int         h, n, x, w, l, t, s;
  AnsiString  szBtnCaption;

  
  if (!IS_MENU_GEN(nodeinfos->WindowStyle)) return;
  // Si le bit 17=1 du Tag : Affichage des boutons déjà fait
  if(( GetParentCTree()->m_pfrmCurrent==NULL) || ( GetParentCTree()->m_pfrmCurrent->ScreenTag & 0x00020000)) return;
  GetParentCTree()->m_pfrmCurrent->ScreenTag |= 0x00020000;

  ASSERT( SCREEN_TAG( GetParentCTree()->m_pfrmCurrent)==nodeinfos->Tag);

  // Calcule le nombre de boutons par theme
  for(int i=0; i<10; i++) BtnCountTheme[i] = BtnByTheme[i] = 0;
  for(int i=0; i<Node->Count; i++) {
	childnodeinfos = GetParentCTree()->FindNode(Node->Item[i]);
	ASSERT( ((childnodeinfos->TagMenu-100)>=0) && ((childnodeinfos->TagMenu-100)<10) );
	if (!IS_CURRENTELEM(childnodeinfos->WindowStyle)) BtnByTheme[childnodeinfos->TagMenu-100]++;
  }

  // Position les boutons dans les différents thèmes
  for(int i=0; i<Node->Count; i++) {
	childnodeinfos = GetParentCTree()->FindNode( Node->Item[i]);
	if (IS_CURRENTELEM(childnodeinfos->WindowStyle)) continue;
	parentctrl     = FindControlTag( GetParentCTree()->m_pfrmCurrent, childnodeinfos->TagMenu);
	ASSERT( parentctrl);

	try {
	  // n : nombre de boutons dans un GroupBox
	  // h : espace entre chaque bouton
	  // x : n ième bouton à afficher dans un GroupBox
	  // t : position y du bouton dans le GroupBox
      // w : la taille du bouton
      // l : la position en x dans le GroupBox
      // s : la taille de l'entête du conteneur
      /*
      n = BtnByTheme[childnodeinfos->TagMenu-100];
      h = (parentctrl->Height - HEIGHT_GRPBOX - (n*HEIGHT_BTN)) / (n+1);
      x = ++BtnCountTheme[childnodeinfos->TagMenu-100];
      t = (h*x) + (HEIGHT_BTN*(x-1)) + HEIGHT_GRPBOX;
      w = (parentctrl->Width*70 / 100);
      l = (parentctrl->Width - w) / 2;
      */
      if ( dynamic_cast<TCustomGroupBox*>( parentctrl)) s = ((TGroupBoxCaption*)parentctrl)->Caption.IsEmpty() ? 0 : HEIGHT_GRPBOX;
                                                   else s = 0;
      n = BtnByTheme[childnodeinfos->TagMenu-100];
      h = (parentctrl->Height - s - (n*HEIGHT_BTN)) / 2;
      x = ++BtnCountTheme[childnodeinfos->TagMenu-100];
      t = HEIGHT_BTN*(x-1) + s + h;
      //w = (parentctrl->Width*70 / 100);
      //l = (parentctrl->Width - w) / 2;
      w = (parentctrl->Width-16);
      l = 8;

      CreateButtonCaption( childnodeinfos, szBtnCaption);
      btnMenu             = new TBitBtn( GetParentCTree()->m_pfrmCurrent);
      btnMenu->OnClick    = GetParentCTree()->OnButtonClick;
      btnMenu->ParentFont = false;
      btnMenu->Caption    = szBtnCaption;
      btnMenu->Tag        = childnodeinfos->Tag;
      btnMenu->Enabled    = IS_ENABLED( childnodeinfos); //childnodeinfos->Enabled;
      btnMenu->Top        = t;
      btnMenu->Left       = l;
      btnMenu->Height     = HEIGHT_BTN;
      btnMenu->Width      = w;
      btnMenu->Margin     = MARGIN_BTN;
      // Charge la propriété glyph avec le bitmap du type d'écran
      int nIndexBmp = childnodeinfos->HaveList ? childnodeinfos->WindowStyle : SCR_MENU;

      Graphics::TBitmap *pBmpEnable     = NULL; pBmpEnable     = new Graphics::TBitmap(); ASSERT( pBmpEnable    );
      Graphics::TBitmap *pBmpDisable    = NULL; pBmpDisable    = new Graphics::TBitmap(); ASSERT( pBmpDisable   );
      Graphics::TBitmap *pBmpGlyph      = NULL; pBmpGlyph      = new Graphics::TBitmap(); ASSERT( pBmpGlyph     );

      if( m_bUseCustomIcons) nIndexBmp = ICON( this, childnodeinfos);

      GetParentCTree()->Images->GetBitmap(  EnableBMP[nIndexBmp], pBmpEnable );
      GetParentCTree()->Images->GetBitmap( DisableBMP[nIndexBmp], pBmpDisable);

      pBmpGlyph->Height = pBmpEnable->Height;
      pBmpGlyph->Width  = pBmpEnable->Width * 2;
      pBmpGlyph->Canvas->Draw(                 0, 0, pBmpEnable );
      pBmpGlyph->Canvas->Draw( pBmpEnable->Width, 0, pBmpDisable);

      CreerTransparenceBmp(pBmpGlyph,
                           pBmpGlyph->Canvas->Pixels[0][0],
                           Color);

      btnMenu->NumGlyphs = ( TNumGlyphs)2;
      btnMenu->Glyph->Assign(pBmpGlyph);

      delete pBmpEnable;
      delete pBmpDisable;
      delete pBmpGlyph;

/*
      if (childnodeinfos->HaveList) Images->GetBitmap(EnableBMP[childnodeinfos->WindowStyle], MenuBtn->Glyph);
      else Images->GetBitmap(EnableBMP[SCR_MENU], MenuBtn->Glyph);
*/
      btnMenu->Parent  = dynamic_cast<TWinControl *>(parentctrl);
    } catch (Exception &e) {
      throw EUser( TAG(50), e);
    }
  }
}
//---------------------------------------------------------------------------
void __fastcall CTree::CloseForm(CEICForm *pForm)
{
  CNodeInfos *nodeinfos = FindNode( SCREEN_TAG( pForm));
  TDBGrid    *pGrid;

  // Si on a un menu liste, on enlève le DataChange du CTREE
  if( nodeinfos->WindowStyle==SCR_LISTE) {
    //ASSERT( nodeinfos->Node);
    if ( nodeinfos->Node )
            CollapseNode( nodeinfos, false);
    if(( pGrid = GetCurrentDBList( pForm))!=NULL) {
//      ASSERT( pGrid->DataSource->OnDataChange==EvOnDataChange);
//      pGrid->DataSource->OnDataChange = m_OnDataChange;
//      m_OnDataChange = NULL;
      TMapDataSource::const_iterator p = m_mapDataChange.find( pGrid->DataSource);
      pGrid->DataSource->OnDataChange = (*p).second;
      //TMapDataSource::iterator q = m_mapDataChange.find( pGrid->DataSource);
      m_mapDataChange.erase( m_mapDataChange.find( pGrid->DataSource));
    }
  } else {
    if(( nodeinfos->WindowStyle==SCR_MENU) && nodeinfos->Node && ( nodeinfos->Node->Parent==NULL))
         CollapseNode( nodeinfos, false);
  }

  m_pfrmCurrent = pForm;
  if ( pForm->OnDeactivate) pForm->OnDeactivate( pForm);
  pForm->OnCloseQuery = NULL;
  pForm->Close();
  delete pForm;          pForm = NULL ;
  m_pPageCtrl->DeleteTitle();
}
//---------------------------------------------------------------------------
bool __fastcall FindCImageMosaic( TWinControl *pWndCtrl)
{
  for( int i=0; i<pWndCtrl->ControlCount; i++) {
    if( AnsiString( pWndCtrl->Controls[i]->ClassName())=="CImageMosaic") return true;
    if( dynamic_cast< TWinControl*>( pWndCtrl->Controls[i])) {
      if( FindCImageMosaic(( TWinControl*)( pWndCtrl->Controls[i]))) return true;
    }
  }
  return false;
}
//---------------------------------------------------------------------------
void __fastcall CTree::SetLoadingScreen( int nTag)
{
  for( int i=0; i<m_pInstances->Count; i++) {
    CTree *pTree = ( CTree*)m_pInstances->Objects[i];
    pTree->m_nLoadingTag = nTag==-1 ? -1 : ( nTag - pTree->FindNode( pTree->FirstNodeTag)->Tag + 1);
  }
}
//---------------------------------------------------------------------------
void __fastcall CTree::LoadScreen(CEICForm **nNewForm, CNodeInfos *nodeinfos)
{
  TCallCreateInstance pfCreateInstance;
  int tag;
  try {
    // Charge la ressource de l'écran
    tag = TAGL;
    SetLoadingScreen( nodeinfos->Tag);
    m_pfrmCurrent    = NULL;
    tag = TAGL;
    pfCreateInstance = GetScreenInstanceProc( nodeinfos); ASSERT( pfCreateInstance);
    tag = TAGL;
    *nNewForm = pfCreateInstance( nodeinfos->Tree);

    tag = TAGL;
    if( Visible)
        if( !FindCImageMosaic(( *nNewForm))) (*nNewForm)->Background->LoadFromResourceName(( int)HInstance, "FOND_ASSISTANT");
    // Change les propriétés de l'écran
    (*nNewForm)->Align       = alNone;
    (*nNewForm)->Visible     = false;
    (*nNewForm)->BorderStyle = bsNone;
    (*nNewForm)->Top         = 0;
    (*nNewForm)->Left        = 0;
    tag = TAGL;
    if (IS_SCR_LISTE(nodeinfos->WindowStyle) && nodeinfos->DisplayBar)
         (*nNewForm)->Height = m_nHeightScr - 30;
    else (*nNewForm)->Height = m_nHeightScr;
    tag = TAGL;
    (*nNewForm)->Width       = m_nWidthScr;
    (*nNewForm)->ScreenTag   = nodeinfos->Tag;
    (*nNewForm)->AutoScroll  = true;
    (*nNewForm)->Parent      = m_pPageCtrl;
    tag = TAGL;

  } catch (Exception &e) {
    SetLoadingScreen( -1);
    throw EUser( /*TAG(48)*/tag, e);
  }
  SetLoadingScreen( -1);
}
//---------------------------------------------------------------------------
void __fastcall CTree::UnLoadScreens()
{
  // Décharge tous les écrans
  for(int i=m_pScrOpen->Count-1; i>=0; i--) {
    CEICForm *pForm = ( CEICForm*)m_pScrOpen->Items[i];
    if ( pForm) CloseForm( pForm);
    m_pScrOpen->Delete(i);
  }
/*
  for(int i=0; i<m_pScrOpen->Count; i++) {
    CEICForm *pForm = ( CEICForm*)m_pScrOpen->Items[i];
    if ( pForm) CloseForm( pForm);
  }
*/
  m_pScrOpen->Clear();
}
//---------------------------------------------------------------------------
void __fastcall CTree::EnableDisableUnderListe( CNodeInfos *parentnodeinfos, bool bTestNode)
{
  CForm     *pForm       = NULL;
  TDBGrid   *pGrid       = NULL;
  bool       bEmptyTable = true;
  TTreeNode *Node        = parentnodeinfos->Node; ASSERT( Node);

  if(( pForm=GetForm( parentnodeinfos->Tag))!=NULL)
    if(( pGrid=GetCurrentDBList( pForm))!=NULL) {
      ASSERT( pGrid->DataSource);
      ASSERT( pGrid->DataSource->DataSet);
      bEmptyTable = pGrid->DataSource->DataSet->IsEmpty();
    }

  for( int i=0; i<Node->Count; i++) {
    CNodeInfos *nodeinfos = FindNode( Node->Item[i]);
    if( IS_CURRENTELEM( nodeinfos->WindowStyle)) {
      if( bEmptyTable) nodeinfos->Node->Text = EmptyStr;
                  else nodeinfos->Node->Text = pGrid->DataSource->DataSet->FieldByName( parentnodeinfos->FieldName)->AsString.UpperCase();
    }
    nodeinfos->EnabledInternal = ( bTestNode ? ( Node==Selected) : true) && !bEmptyTable;
    SetInternalEnableScreen( nodeinfos->Enabled, nodeinfos->Tag);
    if( pForm) {
      TControl *pButton = FindControlTag( dynamic_cast<TWinControl*>( FindControlTag( pForm, nodeinfos->TagMenu)), nodeinfos->Tag);
      if( pButton) pButton->Enabled = IS_ENABLED( nodeinfos);
    }
  }
}
//---------------------------------------------------------------------------
void __fastcall CTree::InitScreenMenu(CEICForm *Form, CNodeInfos *p_nodeinfos)
{
  TDBGrid    *pGrid;
//  TTreeNode  *Node = p_nodeinfos->Node; ASSERT( Node);
//  bool        TableVide;
//  CNodeInfos *nodeinfos;
  // Recherche le DBGrid dans la Form
  if(( pGrid=GetCurrentDBList( Form))==NULL) return;
  // Installe le gestionnaire d'évènement sur le OnDataChange du DataSource
  ASSERT( pGrid->DataSource);
  if(( pGrid->DataSource->OnDataChange!=EvOnDataChange) && ( m_mapDataChange.find( pGrid->DataSource)==m_mapDataChange.end())) {
    m_mapDataChange.insert( TMapDataSource::value_type( pGrid->DataSource, pGrid->DataSource->OnDataChange));
    pGrid->DataSource->OnDataChange = EvOnDataChange;
    /*ASSERT( m_OnDataChange==NULL);
    m_OnDataChange = pGrid->DataSource->OnDataChange;
    pGrid->DataSource->OnDataChange = EvOnDataChange;*/
  }

  EnableDisableUnderListe( p_nodeinfos, false);


  /*
  // Disable tous les écrans sous une liste si celle-ci est vide
  TableVide = pGrid->DataSource->DataSet->IsEmpty();
  Node = p_nodeinfos->Node;
  // Recherche l'écran de l'élement courant afin de changer sa valeur
  for(int i=0; i<Node->Count; i++) {
    nodeinfos = FindNode(Node->Item[i]);
    if (IS_CURRENTELEM(nodeinfos->WindowStyle)) {
      if (TableVide) nodeinfos->Node->Text = "[nouveau]";
      else nodeinfos->Node->Text = pGrid->DataSource->DataSet->FieldByName(p_nodeinfos->FieldName)->AsString.UpperCase();
    } else {
      if (nodeinfos->MenuCreate) {
        nodeinfos->EnabledInternal = true;
        SetInternalEnableScreen( nodeinfos->Enabled, nodeinfos->Tag);
        TControl *Button = FindControlTag(dynamic_cast<TWinControl *>(FindControlTag(Form, nodeinfos->TagMenu)), nodeinfos->Tag);
        if (Button) Button->Enabled = IS_ENABLED( nodeinfos);//true;
        if (TableVide) SetTextScreen("Création", nodeinfos->Tag);
        else SetTextScreen("Modification", nodeinfos->Tag);
      } else {
        nodeinfos->EnabledInternal = !TableVide;
        SetInternalEnableScreen( nodeinfos->Enabled, nodeinfos->Tag);
        TControl *Button = FindControlTag(dynamic_cast<TWinControl *>(FindControlTag(Form, nodeinfos->TagMenu)), nodeinfos->Tag);
        if (Button) Button->Enabled = IS_ENABLED( nodeinfos);//!TableVide;
      }
    }
  }
*/
}
//---------------------------------------------------------------------------
void __fastcall CTree::InitScreen(CEICForm *Form, CNodeInfos *nodeinfos, int index)
{
  if (nodeinfos->WindowStyle==SCR_LISTE) InitScreenMenu(Form, nodeinfos);

  // Si le bit 16=1 du Tag : Initialisation de la form déjà faite
  if (Form->ScreenTag & 0x00010000) return;
  Form->ScreenTag |= 0x00010000;
  // Initialisation à faire en fonction du type de l'écran
  switch (nodeinfos->WindowStyle) {
    case SCR_CURELMT  : break;
    case SCR_MENU     : break;
    case SCR_SAISIE_M : break;
    case SCR_AFFICH_M : break;
    case SCR_EDITIO_M : break;
    case SCR_COURRI_M : break;
    case SCR_LISTE    : break;
    case SCR_SAISIE_L : break;
    case SCR_AFFICH_L : break;
    case SCR_EDITIO_L : break;
    case SCR_COURRI_L : break;
  }

  if (nodeinfos->MenuCreate)
    SetEnableAllBranche(nodeinfos->Node->Parent);
}
//---------------------------------------------------------------------------
void __fastcall CTree::ChangeScreen(TTreeNode **pNode)
{
  int         scrcount;
//  int         indexinsert;
  int         nCount;
  CEICForm   *pForm;
  CNodeInfos *nodeinfos;

  TTreeNode  *Node = *pNode;

  if( m_bExit) return;

  // Supprimer les écrans dont le level est supérieur au node commun
  if (m_CommonNode) {
    while (m_CommonNode->Level != (scrcount=(m_pScrOpen->Count-1))) {
      pForm = ( CEICForm *)m_pScrOpen->Items[scrcount];
      if( pForm) CloseForm( pForm);
      m_pScrOpen->Delete(scrcount);
    }
//    indexinsert = m_CommonNode->Level+1;
  } else {
    UnLoadScreens();
//    indexinsert = 0;
  }

  if( m_bExitAss) *pNode = Node = m_CommonNode;

  // Charge les écrans jusqu'au sélectionné
  TList *pLoading = new TList();

  while( Node!=m_CommonNode) {
    pLoading->Add( FindNode( Node));
    Node = Node->Parent;
  }

  while(( nCount=pLoading->Count)>0) {
    nodeinfos = ( CNodeInfos*)pLoading->Items[nCount-1];
    pForm     = NULL;
    ASSERT( m_pInstances->Count!=0);
    LoadScreen( &pForm, nodeinfos);
    m_pPageCtrl->AddTitle( pForm, nodeinfos);
    ASSERT( dynamic_cast<CEICForm *>( pForm));
    m_pScrOpen->Add( pForm);
    pLoading->Delete( nCount-1);
  }

  delete pLoading;



  // Affiche le dernier écran de la liste et cache toutes les autres
  for(int i=0; i<m_pScrOpen->Count; i++) {
    m_pfrmCurrent = (CEICForm *)m_pScrOpen->Items[i];
    if (m_pfrmCurrent != NULL) {
      nodeinfos = FindNode( SCREEN_TAG( m_pfrmCurrent));
      InitScreen(m_pfrmCurrent, nodeinfos, i);
      if (( m_pfrmCurrent->Visible) && m_pfrmCurrent->OnDeactivate)
        m_pfrmCurrent->OnDeactivate( m_pfrmCurrent);
      m_pfrmCurrent->Visible = false;  //(i==(m_ScreensOpen->Count-1));
    }
  }

  // Grise les boutons Return, Prior et Next de l'appli
  // Fini l'initialisation de l'écran
  DisableSystemButtons();
  m_pPageCtrl->Draw();
  m_pfrmCurrent->Visible = true;
  if ( m_pfrmCurrent->OnActivate) m_pfrmCurrent->OnActivate( m_pfrmCurrent);

  // Initialise les boutons Print et Preview
  RefreshPrintPreview();
}
//---------------------------------------------------------------------------
/***************************************************************************/
/*
/*  Les fonctions évènementielles
/*
/*  Fonctions:
/*  ----------
/*    OnButtonClick    -> Lorque l'on clique sur un bouton dans un
/*                        écran menu
/*    EvOnClickReturn  -> Lorsque que l'on clique sur le bouton
/*                        return dans l'application
/*    EvOnClickPrior   -> Lorsque que l'on clique sur le bouton
/*                        prior dans l'application
/*    EvOnClickNext    -> Lorsque que l'on clique sur le bouton
/*                        next dans l'application
/*    EvOnClickPrint   -> Lorsque que l'on clique sur le bouton
/*                        print dans l'application
/*    EvOnClickPreview -> Lorsque que l'on clique sur le bouton
/*                        preview dans l'application
/*    EvOnDeletion     -> Lorque l'on supprime un node
/*    EvOnChange       -> Change d'écran actif
/*    EvOnChanging     -> Détermine si l'on peut quitter un écran
/*    EvOnExpanding    -> Détermine si l'on peut afficher les écrans
/*                        fils
/*    EvOnDataChange   -> Déroute le OnDataChange du DataSource de
/*                        la liste
/*    EvOnFormKeyDown  -> Déroute le OnKeyDown de la Form principale
/*                        pour pouvoir intercepter les touches Esc,
/*                        Pg_up et Pg_down
/*    EvOnCloseQuery   -> Remplace la OnCloseQuery du parent du Ctree
/*                        pour éviter de sortir d'un écran de l'assistant
/*                        sans vérification de son CloseQuery
/*
/***************************************************************************/
//---------------------------------------------------------------------------
void __fastcall CTree::OnButtonClick(TObject *Sender)
{
  TButton *pButton = dynamic_cast<TButton*>( Sender);
     if ( !pButton) return;

  SetSelectedMenuInternal( pButton->Tag);
}
//---------------------------------------------------------------------------
void __fastcall CTree::EvOnClickReturn(TObject *Sender)
{
  Return();
}
//---------------------------------------------------------------------------
void __fastcall CTree::EvOnClickPrior(TObject *Sender)
{
  Prior();
}
//---------------------------------------------------------------------------
void __fastcall CTree::EvOnClickNext(TObject *Sender)
{
  Next();
}
//---------------------------------------------------------------------------
void __fastcall CTree::EvOnClickPrint(TObject *Sender)
{
  ASSERT( dynamic_cast<CEICForm*>( m_pfrmCurrent));
  (( CEICForm*)m_pfrmCurrent)->OnPrint( Sender);
}
//---------------------------------------------------------------------------
void __fastcall CTree::EvOnClickPreview(TObject *Sender)
{
  ASSERT( dynamic_cast<CEICForm*>( m_pfrmCurrent));
  (( CEICForm*)m_pfrmCurrent)->OnPreview( Sender);
}
//---------------------------------------------------------------------------
void __fastcall CTree::EvOnDeletion (TObject *Sender, TTreeNode *Node)
{
  if (Node) FindNode(Node)->Node = NULL;
}
//---------------------------------------------------------------------------
void __fastcall CTree::SetDrophilitedNode( bool bValue, TTreeNode *pNode)
{
  TV_ITEM pItem;
  pItem.mask      = TVIF_STATE;
  pItem.hItem     = pNode->ItemId;
  pItem.state     = bValue ? TVIS_DROPHILITED : 0;
  pItem.stateMask = TVIS_DROPHILITED;

  TreeView_SetItem( Handle, &pItem);
}
//---------------------------------------------------------------------------
void __fastcall CTree::EvOnChange(TObject *Sender, TTreeNode *Node)
{
  if( Node==NULL) return;

  if( (_CodePartenaire==ecp_Fiduciaire_DR) || (_CodePartenaire==ecp_Fiduciaire_TP)) SetDrophilitedNode( true, Node);
  if( m_pNodeCollapsing!=Node) Node->Expand( false);
  Refresh();

  CNodeInfos *nodeinfos = FindNode( Node);
  // Appel le OnClick du parent du bouton cliqué
  if( IS_MENU_GEN( FindNode( nodeinfos->TagParent)->WindowStyle)) {
    TButton *pButton = GetMenuButton( nodeinfos);
    if( pButton) {
      class TMyWinControl : public TWinControl {
        public:
          __fastcall TMyWinControl( TComponent *pOwner) : TWinControl( pOwner) { };
          __property OnClick;
      };
      TMyWinControl *pWinCtrl = ( TMyWinControl*)( dynamic_cast<TWinControl*>( pButton->Parent));
      if( pWinCtrl && pWinCtrl->OnClick) pWinCtrl->OnClick( pButton);
    }
  }

  ChangeScreen( &Node); nodeinfos = FindNode( Node); // Réaffectation du nodeinfos car le Node peut-être modifié par ChangeScreen
  DisplayButtons( Node, nodeinfos);
  if( m_pfncOnChangeScreen) m_pfncOnChangeScreen( nodeinfos->Tag, this);
  ::PostMessage( Handle, WM_SCRSETFOCUS, 0, 0); // Donne le focus au premier composant du nouvel écran

  m_pNodeCollapsing = NULL;
}
//---------------------------------------------------------------------------
void __fastcall CTree::EvOnChanging(TObject *Sender, TTreeNode *Node, bool &AllowChange)
{
  if( Node==NULL) return;

  CNodeInfos *nodeinfos = FindNode(Node);

  // Si l'on clique sur l'élément courant, on affiche le menu
  // parent, celui qui contient la liste
  if (IS_CURRENTELEM(nodeinfos->WindowStyle)) {
    AllowChange = false; SetSelectedScreen(nodeinfos->TagParent);
    return;
  }

  if( m_pfncOnChangingScreen) {
    m_pfncOnChangingScreen( nodeinfos->Tag, this, AllowChange);
    if( !AllowChange) return;
  }
  if ((AllowChange=IS_ENABLED( nodeinfos)) == false) return;
  if(    ((_CodePartenaire==ecp_Fiduciaire_DR) || (_CodePartenaire==ecp_Fiduciaire_TP))
      && AllowChange && Selected) SetDrophilitedNode( false, Selected);

  bool error   = false;
  m_CommonNode = FindCommonParent(Selected, Node, error);
  if( error) {
    AllowChange = false;
    bool bFocus = ( Selected!=m_CommonNode);
    Selected    = m_CommonNode;
    if( bFocus) ::PostMessage( Handle, WM_SCRSETFOCUS, 0, 0);
  }
}
//---------------------------------------------------------------------------
void __fastcall CTree::EvOnExpanding(TObject *Sender, TTreeNode *Node, bool &AllowExpansion)
{
  CNodeInfos *nodeinfos = FindNode( Node);

  AllowExpansion = IS_ENABLED( nodeinfos);
  if( !IS_MENULISTE( nodeinfos->WindowStyle)) return;

  if( Node!=Selected) EnableDisableUnderListe( nodeinfos, true);
}
//---------------------------------------------------------------------------
void __fastcall CTree::EvOnCollapsing( TObject *Sender, TTreeNode *Node, bool &AllowCollapse)
{
  AllowCollapse = ( Node->Parent!=NULL) || m_bCanCollapse;
  m_pNodeCollapsing = Node;
}
//---------------------------------------------------------------------------
void __fastcall CTree::EvOnDataChange(TObject *Sender, TField *Field)
{
  if (!Field && m_pfrmCurrent) {
    ChangeCurrentElement(m_pfrmCurrent);
    m_pPageCtrl->EvOnDataChange(Sender, Field);
  }
  // Rappel l'ancien gestionnaire OnDataChange
  //if (m_OnDataChange) m_OnDataChange(Sender, Field);
  TMapDataSource::const_iterator p = m_mapDataChange.find( dynamic_cast<TDataSource*>( Sender));
  if((*p).second) (*p).second( Sender, Field);
}
//---------------------------------------------------------------------------
void __fastcall CTree::EvOnFormKeyDown(TObject* Sender, Word &Key, TShiftState Shift)
{
  if ( !Shift.Contains( ssShift) && !Shift.Contains( ssCtrl) && !Shift.Contains( ssAlt)) {
    switch (Key) {
      case VK_NEXT   : ::PostMessage(Handle, WM_NEXT  , 0, 0); break;
      case VK_PRIOR  : ::PostMessage(Handle, WM_PRIOR , 0, 0); break;
      case VK_ESCAPE : ::PostMessage(Handle, WM_RETURN, 0, 0); break;
    }
  }

  // Si l'on est dans un écran de menu, on vérifie que la touche
  // appuyer correspond à un écran
  if( IS_MENU_GEN( FindNode( Selected)->WindowStyle) && !dynamic_cast<TCustomEdit*>( m_pMainForm->ActiveControl) &&
      !dynamic_cast<TCustomGrid*>( m_pMainForm->ActiveControl) &&
    ((( Key>='A') && ( Key<='Z')) || (( Key>='1') && ( Key<='9')))) {
    char cLevel;
    if(( Key>='A') && ( Key<='Z')) cLevel = ( Key - 'A');
                              else cLevel = ( Key - '0') + 25;
    for( int i=Selected->Count-1; i>=0; i--) {
      if( !IS_CURRENTELEM(FindNode( Selected->Item[i])->WindowStyle) && FindNode( Selected->Item[i])->Level==cLevel) {
        SetSelectedScreen( TAG_NODE( Selected->Item[i]));
        break;
      }
    }
  }

  // Rappel l'ancien gestionnaire
  if (m_pOnKeyDown) m_pOnKeyDown(Sender, Key, Shift);
  if (m_pfrmCurrent && m_pfrmCurrent->OnKeyDown) m_pfrmCurrent->OnKeyDown( Sender, Key, Shift);
}
//---------------------------------------------------------------------------
void __fastcall CTree::EvOnFormKeyUp( TObject* Sender, Word &Key, TShiftState Shift)
{
  if (m_pOnKeyUp) m_pOnKeyUp( Sender, Key, Shift);
  if (m_pfrmCurrent && m_pfrmCurrent->OnKeyUp) m_pfrmCurrent->OnKeyUp( Sender, Key, Shift);
}
//---------------------------------------------------------------------------
void __fastcall CTree::EvOnFormKeyPress(TObject* Sender, char &Key)
{
  if (m_pOnKeyPress) m_pOnKeyPress( Sender, Key);
  if (m_pfrmCurrent && m_pfrmCurrent->OnKeyPress) m_pfrmCurrent->OnKeyPress( Sender, Key);
}
//---------------------------------------------------------------------------
void __fastcall CTree::EvOnCloseQuery(TObject *Sender, bool &CanClose)
{
  //SetSelectedMenuInternal(1);
  //CanClose = ((GetSelectedScreen()==1) && m_pfrmCurrent->CloseQuery());
/*
  static bEntry = false;
  if ( bEntry) return;
       bEntry = true;
*/
  if ( m_bExit || !Items->Count) return;
  m_bOnCloseQueryEnCours = true;

  ASSERT( Items->Count);
  int nFirstTag = TAG_NODE( Items->Item[0]); // Récupère le numéro du premier node de l'arbre
  SetSelectedMenuInternal( nFirstTag);
  CanClose = ((GetSelectedScreen()==nFirstTag) && m_pfrmCurrent->CloseQuery());
  if ( CanClose) {
    TForm             *pfrmParent;
    pfrmParent = dynamic_cast<TForm *>(Parent);
    ASSERT( pfrmParent); pfrmParent->OnCloseQuery = NULL;
    CloseForm( m_pfrmCurrent);
    m_bExit = true; m_pfrmCurrent = NULL; m_pScrOpen->Clear();
    if ( m_pfncOnClose) m_pfncOnClose( this);
  }
  m_bOnCloseQueryEnCours = false;
}
//---------------------------------------------------------------------------
bool __fastcall CTree::OnCloseQueryEnCours()
{
return m_bOnCloseQueryEnCours;
}
/***************************************************************************/
/*
/*  Nouveau gestionnaire d'événements
/*
/*  Fonctions:
/*  ----------
/*    WndProc
/*
/***************************************************************************/
//---------------------------------------------------------------------------
void __fastcall CTree::WMSetSelMenu(TMessage &Msg)
{
  SetSelectedMenuInternal(Msg.LParam);
}
//---------------------------------------------------------------------------
void __fastcall CTree::WMReturn(TMessage &Msg) { Return(); }
//---------------------------------------------------------------------------
void __fastcall CTree::WMPrior(TMessage &Msg)  {  Prior(); }
//---------------------------------------------------------------------------
void __fastcall CTree::WMNext(TMessage &Msg)   {  Next();  }
//---------------------------------------------------------------------------
bool __fastcall AllDisable( TWinControl *pForm)
{
  bool         bDisable = true;
  TWinControl *pControl = NULL;
  for( int i=0; i<pForm->ControlCount; i++) {
    pControl = dynamic_cast< TWinControl*>( pForm->Controls[i]);
    if ( pControl) {
      if (( dynamic_cast<TCustomPanel        *>( pControl)!=NULL) ||
          ( dynamic_cast<TCustomGroupBox     *>( pControl)!=NULL) ||
          ( dynamic_cast<TScrollingWinControl*>( pControl)!=NULL))
           bDisable &= AllDisable( pControl);
      else bDisable &= !pControl->Enabled || !pControl->TabStop;
    }
  }
  return bDisable;
}
//---------------------------------------------------------------------------
void __fastcall CTree::WMScrSetFocus( TMessage &Msg)
{
  if( m_bExit || !m_pfrmCurrent) return;
  ASSERT( m_pfrmCurrent);
  // Je donne le focus à la 'Form' courante et je passe au composant
  // suivant tant que ce n'est pas un descendant de 'TCustomControl' pour éviter
  // les panels et autres ...
  bool      bFindComponent;
  TControl *pControl = NULL;
  TForm    *pForm    = ( TForm*)::GetParentForm( this);
  m_pfrmCurrent->SetFocus();
  if( AllDisable( m_pfrmCurrent)) return;
  if( pForm->ActiveControl!=m_pfrmCurrent) return;
  do {
    if ( pControl==pForm->ActiveControl) return;
    TWinControl *pwCtrl = pForm->ActiveControl;
    ::SendMessage( pForm->Handle, WM_NEXTDLGCTL, 0, FALSE);
    if( pForm->ActiveControl==pwCtrl) return;
    bFindComponent = ( dynamic_cast<TCustomPanel        *>( pForm->ActiveControl)==NULL) &&
                     ( dynamic_cast<TCustomGroupBox     *>( pForm->ActiveControl)==NULL) &&
                     ( dynamic_cast<TScrollingWinControl*>( pForm->ActiveControl)==NULL);
    if ( pForm->ActiveControl==m_pfrmCurrent) return;
  } while ( !bFindComponent);

  if( m_hwndFocusedAfterError) ::SetFocus( m_hwndFocusedAfterError);
      m_hwndFocusedAfterError = NULL;

  //  pForm->ActiveControl->Invalidate();
}
//---------------------------------------------------------------------------
void __fastcall CTree::WMKeyDown(TWMKeyDown &Msg)
{
  if ((Msg.CharCode==VK_UP  ) || (Msg.CharCode==VK_DOWN ) ||
      (Msg.CharCode==VK_LEFT) || (Msg.CharCode==VK_RIGHT)) return;

  if (( ::GetKeyState( VK_SHIFT) & 0x8000) || ( ::GetKeyState( VK_CONTROL) & 0x8000)) {
  } else {
    if ((Msg.CharCode==VK_PRIOR) && (Msg.Msg==WM_KEYDOWN)) { Prior(); return; }
    if ((Msg.CharCode==VK_NEXT ) && (Msg.Msg==WM_KEYDOWN)) { Next (); return; }
  }

  TCustomTreeView::Dispatch(&Msg);
}
//---------------------------------------------------------------------------
void __fastcall CTree::WMDestroy( TMessage &Msg)
{
  TCustomTreeView::Dispatch(&Msg);
}
//---------------------------------------------------------------------------
void __fastcall CTree::FermerSplash()
{
  if (Splash)
    {
      delete *Splash;
      *Splash = NULL;
      Splash = NULL;
    }
}
//---------------------------------------------------------------------------
void __fastcall CTree::RefreshPrintPreview()
{
  ASSERT( dynamic_cast< CEICForm*>( m_pfrmCurrent));
  SetButtonAction( BA_PRINT  , (( CEICForm*)m_pfrmCurrent)->OnPrint  !=NULL);
  SetButtonAction( BA_PREVIEW, (( CEICForm*)m_pfrmCurrent)->OnPreview!=NULL);
}
//---------------------------------------------------------------------------
void __fastcall CTree::SetPanelPageFooter( TPanel *pnlPageFooter)
{
  if( m_pnlPageFooter && ( m_pnlPageFooter!=pnlPageFooter))
      m_pnlPageFooter->Parent = dynamic_cast<TWinControl*>( m_pnlPageFooter->Owner);

  m_pnlPageFooter = pnlPageFooter;

  if( PageFooter && m_pPageCtrl) {
    PageFooter->Align  = alBottom;
    PageFooter->Parent = m_pPageCtrl;
    m_pPageCtrl->Draw();
  }
}
//---------------------------------------------------------------------------
CTree *__fastcall CTree::GetParentCTree()
{
  return m_pPushInCTree ? m_pPushInCTree->GetParentCTree() : this;
}
//---------------------------------------------------------------------------
__fastcall CNodeInfos::CNodeInfos( TNodeInfos &infos, CTree *pTree)
{
  m_InstanceIndex   = 0;
  m_Visible         = infos.Visible;
  m_Enabled         = infos.Enabled;
  m_WindowStyle     = infos.WindowStyle;
  m_Tag             = infos.Tag;
  m_TagParent       = infos.TagParent;
  m_TagMenu         = infos.TagMenu;
  m_Text            = infos.Text;
  m_ClassName       = infos.ClassName;
  m_DefineName      = infos.DefineName;
  m_MenuCreate      = infos.MenuCreate;
  m_KeyField        = infos.KeyField;
  m_ListField       = infos.ListField;
  m_Mode            = infos.Mode;
  m_DisplayBar      = infos.DisplayBar;
  m_FieldName       = infos.FieldName;
  m_HaveList        = infos.HaveList;
  m_Level           = infos.Level;
  m_EnabledInternal = infos.EnabledInternal;
  m_TagBrother      = infos.TagBrother;
  m_Icon            = infos.Icon;
  m_pTree           = pTree;
  m_Node	    = NULL;
}
//---------------------------------------------------------------------------
__fastcall CScreenProperty::CScreenProperty():inherited( eDesigner, 0)
{
}
//---------------------------------------------------------------------------
TPropertyAttributes __fastcall CScreenProperty::GetAttributes(void)
{
   return (TPropertyAttributes() << paDialog);
}
//---------------------------------------------------------------------------
void __fastcall CScreenProperty::Edit(void)
{
  try {
    TTreeEditor *editor = new TTreeEditor(Application);
    editor->InitCTreeEditor( (CTree *)((TTreeNodes *)GetOrdValue())->Owner, this);
    editor->ScrTree->FullExpand();  // Développe toutes les branches de l'arbre
    editor->ShowModal();
    delete editor;
    Modified();
  } catch (...) {
  }
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
__fastcall CInsertAssistant::CInsertAssistant()
{
  m_pAssistants = NULL;
  m_pAssistants = new TList();
}
//---------------------------------------------------------------------------
__fastcall CInsertAssistant::~CInsertAssistant()
{
  ASSERT( m_pAssistants->Count==0);
  delete m_pAssistants;
}
//---------------------------------------------------------------------------
bool __fastcall CInsertAssistant::PushAssistant( CTree *pTreeAss, int nTag, int nTagBrother, const AnsiString &strFileName, int nOption, TComponent *pOwner, short sMask /* = 0xFFFF */)
{
  TDefAssistant     eDefAss;
  TDefAssistant    *pDefAss;
  TCreateAssistant  pfncCreateAssistant;
  CTree            *pTree;

  m_eError = EA_OK;
  if(( eDefAss.hInstance=::LoadLibrary( strFileName.c_str()))==NULL) {
    m_eError = EA_LOADLIBRARIE_FAIL;
    goto lblNoError;
  }

  m_eError = EA_CREATEINSTANCE_FENMAINASSISTANT_NOT_FOUND;
  if(( pfncCreateAssistant=( TCreateAssistant)::GetProcAddress( eDefAss.hInstance, "@TFenMainAssistant@CreateInstance$qp18Classes@TComponent"))==NULL) goto lblFreeLib;

  m_eError = EA_RUN_NOT_FOUND;
  eDefAss.pRun  = NULL;
  eDefAss.pRun2 = NULL;
  eDefAss.pRun2 =( TRun2Method)::GetProcAddress( eDefAss.hInstance, "_Run2");
  if( !eDefAss.pRun2) eDefAss.pRun=( TRunMethod)::GetProcAddress( eDefAss.hInstance, "_Run");
  if( !eDefAss.pRun2 && !eDefAss.pRun) goto lblFreeLib;

  m_eError = EA_CREATEINSTANCE_FENMAINASSISTANT_FAIL;
  if(( eDefAss.pFenMainAssistant=pfncCreateAssistant( pOwner))==NULL) goto lblFreeLib;

  eDefAss.pFenMainAssistant->Tag = nOption;

  m_eError = EA_TREE_NOT_FOUND;
  for( int i=eDefAss.pFenMainAssistant->ComponentCount-1; i>=0; i--)
    if( dynamic_cast< CTree*>( eDefAss.pFenMainAssistant->Components[i])) pTree = ( CTree*)eDefAss.pFenMainAssistant->Components[i];
  if( !pTree) goto lblFreeForm;

  m_eError = EA_INITASSISTANT_FAIL;
  if( !pTree->InitAssistant( eDefAss.hInstance, sMask)) goto lblFreeForm;

  if( eDefAss.pRun2)
    eDefAss.pRun2( RA_START, eDefAss.pFenMainAssistant);
  else
    eDefAss.pRun( RA_START);
  eDefAss.nIndex = pTreeAss->InsertAssistant( nTag, nTagBrother, pTree);
  eDefAss.nTag   = nTag;
  eDefAss.pTree  = pTreeAss;

   pDefAss = new TDefAssistant();
  *pDefAss = eDefAss;
  m_pAssistants->Add( pDefAss);

  m_eError = EA_OK;
  goto lblNoError;

lblFreeForm:
  delete eDefAss.pFenMainAssistant;
lblFreeLib:
  ::FreeLibrary( eDefAss.hInstance);

lblNoError:
  return ( m_eError==EA_OK);
}
//---------------------------------------------------------------------------
bool __fastcall CInsertAssistant::PopAssistant()
{
  TDefAssistant *pDefAss;

  ASSERT( m_pAssistants->Count);

  pDefAss  = ( TDefAssistant*)m_pAssistants->Items[m_pAssistants->Count-1];
  m_eError = EA_OK;
  // ATTENTION ! Les 2 lignes suivantes doivent être dans ce sens pour
  // la récursivité d'insertion d'arbre (voir TAX'PRO)
  pDefAss->pTree->DeleteAssistant( pDefAss->nTag, pDefAss->nIndex);
  if( pDefAss->pRun2)
    pDefAss->pRun2( RA_EXIT, pDefAss->pFenMainAssistant);
  else
    pDefAss->pRun( RA_EXIT);
  //-------------------------------------------------------------------------
  delete pDefAss->pFenMainAssistant;
  if( !::FreeLibrary( pDefAss->hInstance)) m_eError = EA_UNLOADLIBRARIE_FAIL;
  delete pDefAss;
  m_pAssistants->Delete( m_pAssistants->Count-1);
  return ( m_eError==EA_OK);
}
//---------------------------------------------------------------------------
bool __fastcall CInsertAssistant::PopAllAssistants()
{
  bool bReturn = true;
  while( CountPushedAssistants) bReturn &= PopAssistant();
  return bReturn;
}
//---------------------------------------------------------------------------
int __fastcall CInsertAssistant::GetCount()
{
  return m_pAssistants->Count;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
CTree *__fastcall GetActiveTree()
{
  TForm *pForm = Screen->ActiveForm; ASSERT( pForm);

  for( int i=pForm->ControlCount-1; i>=0; i--)
    if( dynamic_cast<CTree*>( pForm->Controls[i])) return ( CTree*)pForm->Controls[i];

  return NULL;
}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
namespace Ctreex
{
    void __fastcall PACKAGE Register()
    {
        TComponentClass classes[1] = {__classid(CTree)};
        RegisterComponents("EIC Outils", classes, 0);
        RegisterPropertyEditor(__typeinfo(TTreeNodes), __classid(CTree), "Items", __classid(CScreenProperty));
    }
}
//---------------------------------------------------------------------------


